Merge pull request #1708 from alexanderkyte/always_use_imt
[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  */
12
13 #include <config.h>
14
15 #ifndef DISABLE_JIT
16
17 #include <signal.h>
18
19 #ifdef HAVE_UNISTD_H
20 #include <unistd.h>
21 #endif
22
23 #include <math.h>
24 #include <string.h>
25 #include <ctype.h>
26
27 #ifdef HAVE_SYS_TIME_H
28 #include <sys/time.h>
29 #endif
30
31 #ifdef HAVE_ALLOCA_H
32 #include <alloca.h>
33 #endif
34
35 #include <mono/utils/memcheck.h>
36 #include "mini.h"
37 #include <mono/metadata/abi-details.h>
38 #include <mono/metadata/assembly.h>
39 #include <mono/metadata/attrdefs.h>
40 #include <mono/metadata/loader.h>
41 #include <mono/metadata/tabledefs.h>
42 #include <mono/metadata/class.h>
43 #include <mono/metadata/object.h>
44 #include <mono/metadata/exception.h>
45 #include <mono/metadata/opcodes.h>
46 #include <mono/metadata/mono-endian.h>
47 #include <mono/metadata/tokentype.h>
48 #include <mono/metadata/tabledefs.h>
49 #include <mono/metadata/marshal.h>
50 #include <mono/metadata/debug-helpers.h>
51 #include <mono/metadata/mono-debug.h>
52 #include <mono/metadata/gc-internal.h>
53 #include <mono/metadata/security-manager.h>
54 #include <mono/metadata/threads-types.h>
55 #include <mono/metadata/security-core-clr.h>
56 #include <mono/metadata/monitor.h>
57 #include <mono/metadata/profiler-private.h>
58 #include <mono/metadata/profiler.h>
59 #include <mono/metadata/debug-mono-symfile.h>
60 #include <mono/utils/mono-compiler.h>
61 #include <mono/utils/mono-memory-model.h>
62 #include <mono/metadata/mono-basic-block.h>
63
64 #include "trace.h"
65
66 #include "ir-emit.h"
67
68 #include "jit-icalls.h"
69 #include "jit.h"
70 #include "debugger-agent.h"
71 #include "seq-points.h"
72
73 #define BRANCH_COST 10
74 #define INLINE_LENGTH_LIMIT 20
75
76 /* These have 'cfg' as an implicit argument */
77 #define INLINE_FAILURE(msg) do {                                                                        \
78         if ((cfg->method != cfg->current_method) && (cfg->current_method->wrapper_type == MONO_WRAPPER_NONE)) { \
79                 inline_failure (cfg, msg);                                                                              \
80                 goto exception_exit;                                                                                    \
81         } \
82         } while (0)
83 #define CHECK_CFG_EXCEPTION do {\
84                 if (cfg->exception_type != MONO_EXCEPTION_NONE) \
85                         goto exception_exit;                                            \
86         } while (0)
87 #define METHOD_ACCESS_FAILURE(method, cmethod) do {                     \
88                 method_access_failure ((cfg), (method), (cmethod));                     \
89                 goto exception_exit;                                                                            \
90         } while (0)
91 #define FIELD_ACCESS_FAILURE(method, field) do {                                        \
92                 field_access_failure ((cfg), (method), (field));                        \
93                 goto exception_exit;    \
94         } while (0)
95 #define GENERIC_SHARING_FAILURE(opcode) do {            \
96                 if (cfg->gshared) {                                                                     \
97                         gshared_failure (cfg, opcode, __FILE__, __LINE__);      \
98                         goto exception_exit;    \
99                 }                       \
100         } while (0)
101 #define GSHAREDVT_FAILURE(opcode) do {          \
102         if (cfg->gsharedvt) {                                                                                           \
103                 gsharedvt_failure (cfg, opcode, __FILE__, __LINE__);                    \
104                 goto exception_exit;                                                                                    \
105         }                                                                                                                                       \
106         } while (0)
107 #define OUT_OF_MEMORY_FAILURE do {      \
108                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_OUT_OF_MEMORY);             \
109                 goto exception_exit;    \
110         } while (0)
111 #define DISABLE_AOT(cfg) do { \
112                 if ((cfg)->verbose_level >= 2)                                            \
113                         printf ("AOT disabled: %s:%d\n", __FILE__, __LINE__);   \
114                 (cfg)->disable_aot = TRUE;                                                        \
115         } while (0)
116 #define LOAD_ERROR do { \
117                 break_on_unverified ();                                                         \
118                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD); \
119                 goto exception_exit;                                                                    \
120         } while (0)
121
122 #define TYPE_LOAD_ERROR(klass) do { \
123                 cfg->exception_ptr = klass; \
124                 LOAD_ERROR;                                     \
125         } while (0)
126
127 #define CHECK_CFG_ERROR do {\
128                 if (!mono_error_ok (&cfg->error)) { \
129                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);        \
130                         goto mono_error_exit; \
131                 } \
132         } while (0)
133
134 /* Determine whenever 'ins' represents a load of the 'this' argument */
135 #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && ((ins)->opcode == OP_MOVE) && ((ins)->sreg1 == cfg->args [0]->dreg))
136
137 static int ldind_to_load_membase (int opcode);
138 static int stind_to_store_membase (int opcode);
139
140 int mono_op_to_op_imm (int opcode);
141 int mono_op_to_op_imm_noemul (int opcode);
142
143 MONO_API MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
144
145 static int inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
146                                                   guchar *ip, guint real_offset, gboolean inline_always, MonoBasicBlock **out_cbb);
147
148 /* helper methods signatures */
149 static MonoMethodSignature *helper_sig_class_init_trampoline;
150 static MonoMethodSignature *helper_sig_domain_get;
151 static MonoMethodSignature *helper_sig_generic_class_init_trampoline;
152 static MonoMethodSignature *helper_sig_generic_class_init_trampoline_llvm;
153 static MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline;
154 static MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline;
155 static MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline_llvm;
156 static MonoMethodSignature *helper_sig_monitor_enter_v4_trampoline_llvm;
157
158 /*
159  * Instruction metadata
160  */
161 #ifdef MINI_OP
162 #undef MINI_OP
163 #endif
164 #ifdef MINI_OP3
165 #undef MINI_OP3
166 #endif
167 #define MINI_OP(a,b,dest,src1,src2) dest, src1, src2, ' ',
168 #define MINI_OP3(a,b,dest,src1,src2,src3) dest, src1, src2, src3,
169 #define NONE ' '
170 #define IREG 'i'
171 #define FREG 'f'
172 #define VREG 'v'
173 #define XREG 'x'
174 #if SIZEOF_REGISTER == 8 && SIZEOF_REGISTER == SIZEOF_VOID_P
175 #define LREG IREG
176 #else
177 #define LREG 'l'
178 #endif
179 /* keep in sync with the enum in mini.h */
180 const char
181 ins_info[] = {
182 #include "mini-ops.h"
183 };
184 #undef MINI_OP
185 #undef MINI_OP3
186
187 #define MINI_OP(a,b,dest,src1,src2) ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0)),
188 #define MINI_OP3(a,b,dest,src1,src2,src3) ((src3) != NONE ? 3 : ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0))),
189 /* 
190  * This should contain the index of the last sreg + 1. This is not the same
191  * as the number of sregs for opcodes like IA64_CMP_EQ_IMM.
192  */
193 const gint8 ins_sreg_counts[] = {
194 #include "mini-ops.h"
195 };
196 #undef MINI_OP
197 #undef MINI_OP3
198
199 #define MONO_INIT_VARINFO(vi,id) do { \
200         (vi)->range.first_use.pos.bid = 0xffff; \
201         (vi)->reg = -1; \
202         (vi)->idx = (id); \
203 } while (0)
204
205 guint32
206 mono_alloc_ireg (MonoCompile *cfg)
207 {
208         return alloc_ireg (cfg);
209 }
210
211 guint32
212 mono_alloc_lreg (MonoCompile *cfg)
213 {
214         return alloc_lreg (cfg);
215 }
216
217 guint32
218 mono_alloc_freg (MonoCompile *cfg)
219 {
220         return alloc_freg (cfg);
221 }
222
223 guint32
224 mono_alloc_preg (MonoCompile *cfg)
225 {
226         return alloc_preg (cfg);
227 }
228
229 guint32
230 mono_alloc_dreg (MonoCompile *cfg, MonoStackType stack_type)
231 {
232         return alloc_dreg (cfg, stack_type);
233 }
234
235 /*
236  * mono_alloc_ireg_ref:
237  *
238  *   Allocate an IREG, and mark it as holding a GC ref.
239  */
240 guint32
241 mono_alloc_ireg_ref (MonoCompile *cfg)
242 {
243         return alloc_ireg_ref (cfg);
244 }
245
246 /*
247  * mono_alloc_ireg_mp:
248  *
249  *   Allocate an IREG, and mark it as holding a managed pointer.
250  */
251 guint32
252 mono_alloc_ireg_mp (MonoCompile *cfg)
253 {
254         return alloc_ireg_mp (cfg);
255 }
256
257 /*
258  * mono_alloc_ireg_copy:
259  *
260  *   Allocate an IREG with the same GC type as VREG.
261  */
262 guint32
263 mono_alloc_ireg_copy (MonoCompile *cfg, guint32 vreg)
264 {
265         if (vreg_is_ref (cfg, vreg))
266                 return alloc_ireg_ref (cfg);
267         else if (vreg_is_mp (cfg, vreg))
268                 return alloc_ireg_mp (cfg);
269         else
270                 return alloc_ireg (cfg);
271 }
272
273 guint
274 mono_type_to_regmove (MonoCompile *cfg, MonoType *type)
275 {
276         if (type->byref)
277                 return OP_MOVE;
278
279         type = mini_get_underlying_type (cfg, type);
280 handle_enum:
281         switch (type->type) {
282         case MONO_TYPE_I1:
283         case MONO_TYPE_U1:
284                 return OP_MOVE;
285         case MONO_TYPE_I2:
286         case MONO_TYPE_U2:
287                 return OP_MOVE;
288         case MONO_TYPE_I4:
289         case MONO_TYPE_U4:
290                 return OP_MOVE;
291         case MONO_TYPE_I:
292         case MONO_TYPE_U:
293         case MONO_TYPE_PTR:
294         case MONO_TYPE_FNPTR:
295                 return OP_MOVE;
296         case MONO_TYPE_CLASS:
297         case MONO_TYPE_STRING:
298         case MONO_TYPE_OBJECT:
299         case MONO_TYPE_SZARRAY:
300         case MONO_TYPE_ARRAY:    
301                 return OP_MOVE;
302         case MONO_TYPE_I8:
303         case MONO_TYPE_U8:
304 #if SIZEOF_REGISTER == 8
305                 return OP_MOVE;
306 #else
307                 return OP_LMOVE;
308 #endif
309         case MONO_TYPE_R4:
310                 return cfg->r4fp ? OP_RMOVE : OP_FMOVE;
311         case MONO_TYPE_R8:
312                 return OP_FMOVE;
313         case MONO_TYPE_VALUETYPE:
314                 if (type->data.klass->enumtype) {
315                         type = mono_class_enum_basetype (type->data.klass);
316                         goto handle_enum;
317                 }
318                 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
319                         return OP_XMOVE;
320                 return OP_VMOVE;
321         case MONO_TYPE_TYPEDBYREF:
322                 return OP_VMOVE;
323         case MONO_TYPE_GENERICINST:
324                 type = &type->data.generic_class->container_class->byval_arg;
325                 goto handle_enum;
326         case MONO_TYPE_VAR:
327         case MONO_TYPE_MVAR:
328                 g_assert (cfg->generic_sharing_context);
329                 if (mini_type_var_is_vt (cfg, type))
330                         return OP_VMOVE;
331                 else
332                         return mono_type_to_regmove (cfg, mini_get_underlying_type (cfg, type));
333         default:
334                 g_error ("unknown type 0x%02x in type_to_regstore", type->type);
335         }
336         return -1;
337 }
338
339 void
340 mono_print_bb (MonoBasicBlock *bb, const char *msg)
341 {
342         int i;
343         MonoInst *tree;
344
345         printf ("\n%s %d: [IN: ", msg, bb->block_num);
346         for (i = 0; i < bb->in_count; ++i)
347                 printf (" BB%d(%d)", bb->in_bb [i]->block_num, bb->in_bb [i]->dfn);
348         printf (", OUT: ");
349         for (i = 0; i < bb->out_count; ++i)
350                 printf (" BB%d(%d)", bb->out_bb [i]->block_num, bb->out_bb [i]->dfn);
351         printf (" ]\n");
352         for (tree = bb->code; tree; tree = tree->next)
353                 mono_print_ins_index (-1, tree);
354 }
355
356 void
357 mono_create_helper_signatures (void)
358 {
359         helper_sig_domain_get = mono_create_icall_signature ("ptr");
360         helper_sig_class_init_trampoline = mono_create_icall_signature ("void");
361         helper_sig_generic_class_init_trampoline = mono_create_icall_signature ("void");
362         helper_sig_generic_class_init_trampoline_llvm = mono_create_icall_signature ("void ptr");
363         helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
364         helper_sig_monitor_enter_exit_trampoline = mono_create_icall_signature ("void");
365         helper_sig_monitor_enter_exit_trampoline_llvm = mono_create_icall_signature ("void object");
366         helper_sig_monitor_enter_v4_trampoline_llvm = mono_create_icall_signature ("void object ptr");
367 }
368
369 static MONO_NEVER_INLINE void
370 break_on_unverified (void)
371 {
372         if (mini_get_debug_options ()->break_on_unverified)
373                 G_BREAKPOINT ();
374 }
375
376 static MONO_NEVER_INLINE void
377 method_access_failure (MonoCompile *cfg, MonoMethod *method, MonoMethod *cil_method)
378 {
379         char *method_fname = mono_method_full_name (method, TRUE);
380         char *cil_method_fname = mono_method_full_name (cil_method, TRUE);
381         mono_cfg_set_exception (cfg, MONO_EXCEPTION_METHOD_ACCESS);
382         cfg->exception_message = g_strdup_printf ("Method `%s' is inaccessible from method `%s'\n", cil_method_fname, method_fname);
383         g_free (method_fname);
384         g_free (cil_method_fname);
385 }
386
387 static MONO_NEVER_INLINE void
388 field_access_failure (MonoCompile *cfg, MonoMethod *method, MonoClassField *field)
389 {
390         char *method_fname = mono_method_full_name (method, TRUE);
391         char *field_fname = mono_field_full_name (field);
392         mono_cfg_set_exception (cfg, MONO_EXCEPTION_FIELD_ACCESS);
393         cfg->exception_message = g_strdup_printf ("Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname);
394         g_free (method_fname);
395         g_free (field_fname);
396 }
397
398 static MONO_NEVER_INLINE void
399 inline_failure (MonoCompile *cfg, const char *msg)
400 {
401         if (cfg->verbose_level >= 2)
402                 printf ("inline failed: %s\n", msg);
403         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INLINE_FAILED);
404 }
405
406 static MONO_NEVER_INLINE void
407 gshared_failure (MonoCompile *cfg, int opcode, const char *file, int line)
408 {
409         if (cfg->verbose_level > 2)                                                                                     \
410                 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);
411         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
412 }
413
414 static MONO_NEVER_INLINE void
415 gsharedvt_failure (MonoCompile *cfg, int opcode, const char *file, int line)
416 {
417         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);
418         if (cfg->verbose_level >= 2)
419                 printf ("%s\n", cfg->exception_message);
420         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
421 }
422
423 /*
424  * When using gsharedvt, some instatiations might be verifiable, and some might be not. i.e. 
425  * foo<T> (int i) { ldarg.0; box T; }
426  */
427 #define UNVERIFIED do { \
428         if (cfg->gsharedvt) { \
429                 if (cfg->verbose_level > 2)                                                                     \
430                         printf ("gsharedvt method failed to verify, falling back to instantiation.\n"); \
431                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \
432                 goto exception_exit;                                                                                    \
433         }                                                                                                                                       \
434         break_on_unverified ();                                                                                         \
435         goto unverified;                                                                                                        \
436 } while (0)
437
438 #define GET_BBLOCK(cfg,tblock,ip) do {  \
439                 (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
440                 if (!(tblock)) {        \
441                         if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
442             NEW_BBLOCK (cfg, (tblock)); \
443                         (tblock)->cil_code = (ip);      \
444                         ADD_BBLOCK (cfg, (tblock));     \
445                 } \
446         } while (0)
447
448 #if defined(TARGET_X86) || defined(TARGET_AMD64)
449 #define EMIT_NEW_X86_LEA(cfg,dest,sr1,sr2,shift,imm) do { \
450                 MONO_INST_NEW (cfg, dest, OP_X86_LEA); \
451                 (dest)->dreg = alloc_ireg_mp ((cfg)); \
452                 (dest)->sreg1 = (sr1); \
453                 (dest)->sreg2 = (sr2); \
454                 (dest)->inst_imm = (imm); \
455                 (dest)->backend.shift_amount = (shift); \
456                 MONO_ADD_INS ((cfg)->cbb, (dest)); \
457         } while (0)
458 #endif
459
460 /* Emit conversions so both operands of a binary opcode are of the same type */
461 static void
462 add_widen_op (MonoCompile *cfg, MonoInst *ins, MonoInst **arg1_ref, MonoInst **arg2_ref)
463 {
464         MonoInst *arg1 = *arg1_ref;
465         MonoInst *arg2 = *arg2_ref;
466
467         if (cfg->r4fp &&
468                 ((arg1->type == STACK_R4 && arg2->type == STACK_R8) ||
469                  (arg1->type == STACK_R8 && arg2->type == STACK_R4))) {
470                 MonoInst *conv;
471
472                 /* Mixing r4/r8 is allowed by the spec */
473                 if (arg1->type == STACK_R4) {
474                         int dreg = alloc_freg (cfg);
475
476                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg1->dreg);
477                         conv->type = STACK_R8;
478                         ins->sreg1 = dreg;
479                         *arg1_ref = conv;
480                 }
481                 if (arg2->type == STACK_R4) {
482                         int dreg = alloc_freg (cfg);
483
484                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg2->dreg);
485                         conv->type = STACK_R8;
486                         ins->sreg2 = dreg;
487                         *arg2_ref = conv;
488                 }
489         }
490
491 #if SIZEOF_REGISTER == 8
492         /* FIXME: Need to add many more cases */
493         if ((arg1)->type == STACK_PTR && (arg2)->type == STACK_I4) {
494                 MonoInst *widen;
495
496                 int dr = alloc_preg (cfg);
497                 EMIT_NEW_UNALU (cfg, widen, OP_SEXT_I4, dr, (arg2)->dreg);
498                 (ins)->sreg2 = widen->dreg;
499         }
500 #endif
501 }
502
503 #define ADD_BINOP(op) do {      \
504                 MONO_INST_NEW (cfg, ins, (op)); \
505                 sp -= 2;        \
506                 ins->sreg1 = sp [0]->dreg;      \
507                 ins->sreg2 = sp [1]->dreg;      \
508                 type_from_op (cfg, ins, sp [0], sp [1]);        \
509                 CHECK_TYPE (ins);       \
510                 /* Have to insert a widening op */               \
511         add_widen_op (cfg, ins, &sp [0], &sp [1]);               \
512         ins->dreg = alloc_dreg ((cfg), (ins)->type); \
513         MONO_ADD_INS ((cfg)->cbb, (ins)); \
514         *sp++ = mono_decompose_opcode ((cfg), (ins), &bblock);  \
515         } while (0)
516
517 #define ADD_UNOP(op) do {       \
518                 MONO_INST_NEW (cfg, ins, (op)); \
519                 sp--;   \
520                 ins->sreg1 = sp [0]->dreg;      \
521                 type_from_op (cfg, ins, sp [0], NULL);  \
522                 CHECK_TYPE (ins);       \
523         (ins)->dreg = alloc_dreg ((cfg), (ins)->type); \
524         MONO_ADD_INS ((cfg)->cbb, (ins)); \
525                 *sp++ = mono_decompose_opcode (cfg, ins, &bblock);      \
526         } while (0)
527
528 #define ADD_BINCOND(next_block) do {    \
529                 MonoInst *cmp;  \
530                 sp -= 2; \
531                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
532                 cmp->sreg1 = sp [0]->dreg;      \
533                 cmp->sreg2 = sp [1]->dreg;      \
534                 type_from_op (cfg, cmp, sp [0], sp [1]);        \
535                 CHECK_TYPE (cmp);       \
536                 add_widen_op (cfg, cmp, &sp [0], &sp [1]);                                              \
537                 type_from_op (cfg, ins, sp [0], sp [1]);                                                        \
538                 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);      \
539                 GET_BBLOCK (cfg, tblock, target);               \
540                 link_bblock (cfg, bblock, tblock);      \
541                 ins->inst_true_bb = tblock;     \
542                 if ((next_block)) {     \
543                         link_bblock (cfg, bblock, (next_block));        \
544                         ins->inst_false_bb = (next_block);      \
545                         start_new_bblock = 1;   \
546                 } else {        \
547                         GET_BBLOCK (cfg, tblock, ip);           \
548                         link_bblock (cfg, bblock, tblock);      \
549                         ins->inst_false_bb = tblock;    \
550                         start_new_bblock = 2;   \
551                 }       \
552                 if (sp != stack_start) {                                                                        \
553                     handle_stack_args (cfg, stack_start, sp - stack_start); \
554                         CHECK_UNVERIFIABLE (cfg); \
555                 } \
556         MONO_ADD_INS (bblock, cmp); \
557                 MONO_ADD_INS (bblock, ins);     \
558         } while (0)
559
560 /* *
561  * link_bblock: Links two basic blocks
562  *
563  * links two basic blocks in the control flow graph, the 'from'
564  * argument is the starting block and the 'to' argument is the block
565  * the control flow ends to after 'from'.
566  */
567 static void
568 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
569 {
570         MonoBasicBlock **newa;
571         int i, found;
572
573 #if 0
574         if (from->cil_code) {
575                 if (to->cil_code)
576                         printf ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
577                 else
578                         printf ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
579         } else {
580                 if (to->cil_code)
581                         printf ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
582                 else
583                         printf ("edge from entry to exit\n");
584         }
585 #endif
586
587         found = FALSE;
588         for (i = 0; i < from->out_count; ++i) {
589                 if (to == from->out_bb [i]) {
590                         found = TRUE;
591                         break;
592                 }
593         }
594         if (!found) {
595                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
596                 for (i = 0; i < from->out_count; ++i) {
597                         newa [i] = from->out_bb [i];
598                 }
599                 newa [i] = to;
600                 from->out_count++;
601                 from->out_bb = newa;
602         }
603
604         found = FALSE;
605         for (i = 0; i < to->in_count; ++i) {
606                 if (from == to->in_bb [i]) {
607                         found = TRUE;
608                         break;
609                 }
610         }
611         if (!found) {
612                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
613                 for (i = 0; i < to->in_count; ++i) {
614                         newa [i] = to->in_bb [i];
615                 }
616                 newa [i] = from;
617                 to->in_count++;
618                 to->in_bb = newa;
619         }
620 }
621
622 void
623 mono_link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
624 {
625         link_bblock (cfg, from, to);
626 }
627
628 /**
629  * mono_find_block_region:
630  *
631  *   We mark each basic block with a region ID. We use that to avoid BB
632  *   optimizations when blocks are in different regions.
633  *
634  * Returns:
635  *   A region token that encodes where this region is, and information
636  *   about the clause owner for this block.
637  *
638  *   The region encodes the try/catch/filter clause that owns this block
639  *   as well as the type.  -1 is a special value that represents a block
640  *   that is in none of try/catch/filter.
641  */
642 static int
643 mono_find_block_region (MonoCompile *cfg, int offset)
644 {
645         MonoMethodHeader *header = cfg->header;
646         MonoExceptionClause *clause;
647         int i;
648
649         for (i = 0; i < header->num_clauses; ++i) {
650                 clause = &header->clauses [i];
651                 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
652                     (offset < (clause->handler_offset)))
653                         return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
654                            
655                 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
656                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
657                                 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
658                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
659                                 return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
660                         else
661                                 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
662                 }
663         }
664         for (i = 0; i < header->num_clauses; ++i) {
665                 clause = &header->clauses [i];
666
667                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
668                         return ((i + 1) << 8) | clause->flags;
669         }
670
671         return -1;
672 }
673
674 static GList*
675 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
676 {
677         MonoMethodHeader *header = cfg->header;
678         MonoExceptionClause *clause;
679         int i;
680         GList *res = NULL;
681
682         for (i = 0; i < header->num_clauses; ++i) {
683                 clause = &header->clauses [i];
684                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
685                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
686                         if (clause->flags == type)
687                                 res = g_list_append (res, clause);
688                 }
689         }
690         return res;
691 }
692
693 static void
694 mono_create_spvar_for_region (MonoCompile *cfg, int region)
695 {
696         MonoInst *var;
697
698         var = g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
699         if (var)
700                 return;
701
702         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
703         /* prevent it from being register allocated */
704         var->flags |= MONO_INST_VOLATILE;
705
706         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
707 }
708
709 MonoInst *
710 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
711 {
712         return g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
713 }
714
715 static MonoInst*
716 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
717 {
718         MonoInst *var;
719
720         var = g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
721         if (var)
722                 return var;
723
724         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
725         /* prevent it from being register allocated */
726         var->flags |= MONO_INST_VOLATILE;
727
728         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
729
730         return var;
731 }
732
733 /*
734  * Returns the type used in the eval stack when @type is loaded.
735  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
736  */
737 void
738 type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
739 {
740         MonoClass *klass;
741
742         type = mini_get_underlying_type (cfg, type);
743         inst->klass = klass = mono_class_from_mono_type (type);
744         if (type->byref) {
745                 inst->type = STACK_MP;
746                 return;
747         }
748
749 handle_enum:
750         switch (type->type) {
751         case MONO_TYPE_VOID:
752                 inst->type = STACK_INV;
753                 return;
754         case MONO_TYPE_I1:
755         case MONO_TYPE_U1:
756         case MONO_TYPE_I2:
757         case MONO_TYPE_U2:
758         case MONO_TYPE_I4:
759         case MONO_TYPE_U4:
760                 inst->type = STACK_I4;
761                 return;
762         case MONO_TYPE_I:
763         case MONO_TYPE_U:
764         case MONO_TYPE_PTR:
765         case MONO_TYPE_FNPTR:
766                 inst->type = STACK_PTR;
767                 return;
768         case MONO_TYPE_CLASS:
769         case MONO_TYPE_STRING:
770         case MONO_TYPE_OBJECT:
771         case MONO_TYPE_SZARRAY:
772         case MONO_TYPE_ARRAY:    
773                 inst->type = STACK_OBJ;
774                 return;
775         case MONO_TYPE_I8:
776         case MONO_TYPE_U8:
777                 inst->type = STACK_I8;
778                 return;
779         case MONO_TYPE_R4:
780                 inst->type = cfg->r4_stack_type;
781                 break;
782         case MONO_TYPE_R8:
783                 inst->type = STACK_R8;
784                 return;
785         case MONO_TYPE_VALUETYPE:
786                 if (type->data.klass->enumtype) {
787                         type = mono_class_enum_basetype (type->data.klass);
788                         goto handle_enum;
789                 } else {
790                         inst->klass = klass;
791                         inst->type = STACK_VTYPE;
792                         return;
793                 }
794         case MONO_TYPE_TYPEDBYREF:
795                 inst->klass = mono_defaults.typed_reference_class;
796                 inst->type = STACK_VTYPE;
797                 return;
798         case MONO_TYPE_GENERICINST:
799                 type = &type->data.generic_class->container_class->byval_arg;
800                 goto handle_enum;
801         case MONO_TYPE_VAR:
802         case MONO_TYPE_MVAR:
803                 g_assert (cfg->generic_sharing_context);
804                 if (mini_is_gsharedvt_type (cfg, type)) {
805                         g_assert (cfg->gsharedvt);
806                         inst->type = STACK_VTYPE;
807                 } else {
808                         type_to_eval_stack_type (cfg, mini_get_underlying_type (cfg, type), inst);
809                 }
810                 return;
811         default:
812                 g_error ("unknown type 0x%02x in eval stack type", type->type);
813         }
814 }
815
816 /*
817  * The following tables are used to quickly validate the IL code in type_from_op ().
818  */
819 static const char
820 bin_num_table [STACK_MAX] [STACK_MAX] = {
821         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
822         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
823         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
824         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
825         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV, STACK_R8},
826         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
827         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
828         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
829         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4}
830 };
831
832 static const char 
833 neg_table [] = {
834         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4
835 };
836
837 /* reduce the size of this table */
838 static const char
839 bin_int_table [STACK_MAX] [STACK_MAX] = {
840         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
841         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
842         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
843         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
844         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
845         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
846         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
847         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
848 };
849
850 static const char
851 bin_comp_table [STACK_MAX] [STACK_MAX] = {
852 /*      Inv i  L  p  F  &  O  vt r4 */
853         {0},
854         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
855         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
856         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
857         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* F, R8 */
858         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
859         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
860         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
861         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* r, r4 */
862 };
863
864 /* reduce the size of this table */
865 static const char
866 shift_table [STACK_MAX] [STACK_MAX] = {
867         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
868         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
869         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
870         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
871         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
872         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
873         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
874         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
875 };
876
877 /*
878  * Tables to map from the non-specific opcode to the matching
879  * type-specific opcode.
880  */
881 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
882 static const guint16
883 binops_op_map [STACK_MAX] = {
884         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
885 };
886
887 /* handles from CEE_NEG to CEE_CONV_U8 */
888 static const guint16
889 unops_op_map [STACK_MAX] = {
890         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
891 };
892
893 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
894 static const guint16
895 ovfops_op_map [STACK_MAX] = {
896         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
897 };
898
899 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
900 static const guint16
901 ovf2ops_op_map [STACK_MAX] = {
902         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
903 };
904
905 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
906 static const guint16
907 ovf3ops_op_map [STACK_MAX] = {
908         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
909 };
910
911 /* handles from CEE_BEQ to CEE_BLT_UN */
912 static const guint16
913 beqops_op_map [STACK_MAX] = {
914         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
915 };
916
917 /* handles from CEE_CEQ to CEE_CLT_UN */
918 static const guint16
919 ceqops_op_map [STACK_MAX] = {
920         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
921 };
922
923 /*
924  * Sets ins->type (the type on the eval stack) according to the
925  * type of the opcode and the arguments to it.
926  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
927  *
928  * FIXME: this function sets ins->type unconditionally in some cases, but
929  * it should set it to invalid for some types (a conv.x on an object)
930  */
931 static void
932 type_from_op (MonoCompile *cfg, MonoInst *ins, MonoInst *src1, MonoInst *src2)
933 {
934         switch (ins->opcode) {
935         /* binops */
936         case CEE_ADD:
937         case CEE_SUB:
938         case CEE_MUL:
939         case CEE_DIV:
940         case CEE_REM:
941                 /* FIXME: check unverifiable args for STACK_MP */
942                 ins->type = bin_num_table [src1->type] [src2->type];
943                 ins->opcode += binops_op_map [ins->type];
944                 break;
945         case CEE_DIV_UN:
946         case CEE_REM_UN:
947         case CEE_AND:
948         case CEE_OR:
949         case CEE_XOR:
950                 ins->type = bin_int_table [src1->type] [src2->type];
951                 ins->opcode += binops_op_map [ins->type];
952                 break;
953         case CEE_SHL:
954         case CEE_SHR:
955         case CEE_SHR_UN:
956                 ins->type = shift_table [src1->type] [src2->type];
957                 ins->opcode += binops_op_map [ins->type];
958                 break;
959         case OP_COMPARE:
960         case OP_LCOMPARE:
961         case OP_ICOMPARE:
962                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
963                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
964                         ins->opcode = OP_LCOMPARE;
965                 else if (src1->type == STACK_R4)
966                         ins->opcode = OP_RCOMPARE;
967                 else if (src1->type == STACK_R8)
968                         ins->opcode = OP_FCOMPARE;
969                 else
970                         ins->opcode = OP_ICOMPARE;
971                 break;
972         case OP_ICOMPARE_IMM:
973                 ins->type = bin_comp_table [src1->type] [src1->type] ? STACK_I4 : STACK_INV;
974                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
975                         ins->opcode = OP_LCOMPARE_IMM;          
976                 break;
977         case CEE_BEQ:
978         case CEE_BGE:
979         case CEE_BGT:
980         case CEE_BLE:
981         case CEE_BLT:
982         case CEE_BNE_UN:
983         case CEE_BGE_UN:
984         case CEE_BGT_UN:
985         case CEE_BLE_UN:
986         case CEE_BLT_UN:
987                 ins->opcode += beqops_op_map [src1->type];
988                 break;
989         case OP_CEQ:
990                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
991                 ins->opcode += ceqops_op_map [src1->type];
992                 break;
993         case OP_CGT:
994         case OP_CGT_UN:
995         case OP_CLT:
996         case OP_CLT_UN:
997                 ins->type = (bin_comp_table [src1->type] [src2->type] & 1) ? STACK_I4: STACK_INV;
998                 ins->opcode += ceqops_op_map [src1->type];
999                 break;
1000         /* unops */
1001         case CEE_NEG:
1002                 ins->type = neg_table [src1->type];
1003                 ins->opcode += unops_op_map [ins->type];
1004                 break;
1005         case CEE_NOT:
1006                 if (src1->type >= STACK_I4 && src1->type <= STACK_PTR)
1007                         ins->type = src1->type;
1008                 else
1009                         ins->type = STACK_INV;
1010                 ins->opcode += unops_op_map [ins->type];
1011                 break;
1012         case CEE_CONV_I1:
1013         case CEE_CONV_I2:
1014         case CEE_CONV_I4:
1015         case CEE_CONV_U4:
1016                 ins->type = STACK_I4;
1017                 ins->opcode += unops_op_map [src1->type];
1018                 break;
1019         case CEE_CONV_R_UN:
1020                 ins->type = STACK_R8;
1021                 switch (src1->type) {
1022                 case STACK_I4:
1023                 case STACK_PTR:
1024                         ins->opcode = OP_ICONV_TO_R_UN;
1025                         break;
1026                 case STACK_I8:
1027                         ins->opcode = OP_LCONV_TO_R_UN; 
1028                         break;
1029                 }
1030                 break;
1031         case CEE_CONV_OVF_I1:
1032         case CEE_CONV_OVF_U1:
1033         case CEE_CONV_OVF_I2:
1034         case CEE_CONV_OVF_U2:
1035         case CEE_CONV_OVF_I4:
1036         case CEE_CONV_OVF_U4:
1037                 ins->type = STACK_I4;
1038                 ins->opcode += ovf3ops_op_map [src1->type];
1039                 break;
1040         case CEE_CONV_OVF_I_UN:
1041         case CEE_CONV_OVF_U_UN:
1042                 ins->type = STACK_PTR;
1043                 ins->opcode += ovf2ops_op_map [src1->type];
1044                 break;
1045         case CEE_CONV_OVF_I1_UN:
1046         case CEE_CONV_OVF_I2_UN:
1047         case CEE_CONV_OVF_I4_UN:
1048         case CEE_CONV_OVF_U1_UN:
1049         case CEE_CONV_OVF_U2_UN:
1050         case CEE_CONV_OVF_U4_UN:
1051                 ins->type = STACK_I4;
1052                 ins->opcode += ovf2ops_op_map [src1->type];
1053                 break;
1054         case CEE_CONV_U:
1055                 ins->type = STACK_PTR;
1056                 switch (src1->type) {
1057                 case STACK_I4:
1058                         ins->opcode = OP_ICONV_TO_U;
1059                         break;
1060                 case STACK_PTR:
1061                 case STACK_MP:
1062 #if SIZEOF_VOID_P == 8
1063                         ins->opcode = OP_LCONV_TO_U;
1064 #else
1065                         ins->opcode = OP_MOVE;
1066 #endif
1067                         break;
1068                 case STACK_I8:
1069                         ins->opcode = OP_LCONV_TO_U;
1070                         break;
1071                 case STACK_R8:
1072                         ins->opcode = OP_FCONV_TO_U;
1073                         break;
1074                 }
1075                 break;
1076         case CEE_CONV_I8:
1077         case CEE_CONV_U8:
1078                 ins->type = STACK_I8;
1079                 ins->opcode += unops_op_map [src1->type];
1080                 break;
1081         case CEE_CONV_OVF_I8:
1082         case CEE_CONV_OVF_U8:
1083                 ins->type = STACK_I8;
1084                 ins->opcode += ovf3ops_op_map [src1->type];
1085                 break;
1086         case CEE_CONV_OVF_U8_UN:
1087         case CEE_CONV_OVF_I8_UN:
1088                 ins->type = STACK_I8;
1089                 ins->opcode += ovf2ops_op_map [src1->type];
1090                 break;
1091         case CEE_CONV_R4:
1092                 ins->type = cfg->r4_stack_type;
1093                 ins->opcode += unops_op_map [src1->type];
1094                 break;
1095         case CEE_CONV_R8:
1096                 ins->type = STACK_R8;
1097                 ins->opcode += unops_op_map [src1->type];
1098                 break;
1099         case OP_CKFINITE:
1100                 ins->type = STACK_R8;           
1101                 break;
1102         case CEE_CONV_U2:
1103         case CEE_CONV_U1:
1104                 ins->type = STACK_I4;
1105                 ins->opcode += ovfops_op_map [src1->type];
1106                 break;
1107         case CEE_CONV_I:
1108         case CEE_CONV_OVF_I:
1109         case CEE_CONV_OVF_U:
1110                 ins->type = STACK_PTR;
1111                 ins->opcode += ovfops_op_map [src1->type];
1112                 break;
1113         case CEE_ADD_OVF:
1114         case CEE_ADD_OVF_UN:
1115         case CEE_MUL_OVF:
1116         case CEE_MUL_OVF_UN:
1117         case CEE_SUB_OVF:
1118         case CEE_SUB_OVF_UN:
1119                 ins->type = bin_num_table [src1->type] [src2->type];
1120                 ins->opcode += ovfops_op_map [src1->type];
1121                 if (ins->type == STACK_R8)
1122                         ins->type = STACK_INV;
1123                 break;
1124         case OP_LOAD_MEMBASE:
1125                 ins->type = STACK_PTR;
1126                 break;
1127         case OP_LOADI1_MEMBASE:
1128         case OP_LOADU1_MEMBASE:
1129         case OP_LOADI2_MEMBASE:
1130         case OP_LOADU2_MEMBASE:
1131         case OP_LOADI4_MEMBASE:
1132         case OP_LOADU4_MEMBASE:
1133                 ins->type = STACK_PTR;
1134                 break;
1135         case OP_LOADI8_MEMBASE:
1136                 ins->type = STACK_I8;
1137                 break;
1138         case OP_LOADR4_MEMBASE:
1139                 ins->type = cfg->r4_stack_type;
1140                 break;
1141         case OP_LOADR8_MEMBASE:
1142                 ins->type = STACK_R8;
1143                 break;
1144         default:
1145                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1146                 break;
1147         }
1148
1149         if (ins->type == STACK_MP)
1150                 ins->klass = mono_defaults.object_class;
1151 }
1152
1153 static const char 
1154 ldind_type [] = {
1155         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
1156 };
1157
1158 #if 0
1159
1160 static const char
1161 param_table [STACK_MAX] [STACK_MAX] = {
1162         {0},
1163 };
1164
1165 static int
1166 check_values_to_signature (MonoInst *args, MonoType *this, MonoMethodSignature *sig) {
1167         int i;
1168
1169         if (sig->hasthis) {
1170                 switch (args->type) {
1171                 case STACK_I4:
1172                 case STACK_I8:
1173                 case STACK_R8:
1174                 case STACK_VTYPE:
1175                 case STACK_INV:
1176                         return 0;
1177                 }
1178                 args++;
1179         }
1180         for (i = 0; i < sig->param_count; ++i) {
1181                 switch (args [i].type) {
1182                 case STACK_INV:
1183                         return 0;
1184                 case STACK_MP:
1185                         if (!sig->params [i]->byref)
1186                                 return 0;
1187                         continue;
1188                 case STACK_OBJ:
1189                         if (sig->params [i]->byref)
1190                                 return 0;
1191                         switch (sig->params [i]->type) {
1192                         case MONO_TYPE_CLASS:
1193                         case MONO_TYPE_STRING:
1194                         case MONO_TYPE_OBJECT:
1195                         case MONO_TYPE_SZARRAY:
1196                         case MONO_TYPE_ARRAY:
1197                                 break;
1198                         default:
1199                                 return 0;
1200                         }
1201                         continue;
1202                 case STACK_R8:
1203                         if (sig->params [i]->byref)
1204                                 return 0;
1205                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1206                                 return 0;
1207                         continue;
1208                 case STACK_PTR:
1209                 case STACK_I4:
1210                 case STACK_I8:
1211                 case STACK_VTYPE:
1212                         break;
1213                 }
1214                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1215                         return 0;*/
1216         }
1217         return 1;
1218 }
1219 #endif
1220
1221 /*
1222  * When we need a pointer to the current domain many times in a method, we
1223  * call mono_domain_get() once and we store the result in a local variable.
1224  * This function returns the variable that represents the MonoDomain*.
1225  */
1226 inline static MonoInst *
1227 mono_get_domainvar (MonoCompile *cfg)
1228 {
1229         if (!cfg->domainvar)
1230                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1231         return cfg->domainvar;
1232 }
1233
1234 /*
1235  * The got_var contains the address of the Global Offset Table when AOT 
1236  * compiling.
1237  */
1238 MonoInst *
1239 mono_get_got_var (MonoCompile *cfg)
1240 {
1241 #ifdef MONO_ARCH_NEED_GOT_VAR
1242         if (!cfg->compile_aot)
1243                 return NULL;
1244         if (!cfg->got_var) {
1245                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1246         }
1247         return cfg->got_var;
1248 #else
1249         return NULL;
1250 #endif
1251 }
1252
1253 static MonoInst *
1254 mono_get_vtable_var (MonoCompile *cfg)
1255 {
1256         g_assert (cfg->generic_sharing_context);
1257
1258         if (!cfg->rgctx_var) {
1259                 cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1260                 /* force the var to be stack allocated */
1261                 cfg->rgctx_var->flags |= MONO_INST_VOLATILE;
1262         }
1263
1264         return cfg->rgctx_var;
1265 }
1266
1267 static MonoType*
1268 type_from_stack_type (MonoInst *ins) {
1269         switch (ins->type) {
1270         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1271         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1272         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1273         case STACK_R4: return &mono_defaults.single_class->byval_arg;
1274         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1275         case STACK_MP:
1276                 return &ins->klass->this_arg;
1277         case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1278         case STACK_VTYPE: return &ins->klass->byval_arg;
1279         default:
1280                 g_error ("stack type %d to monotype not handled\n", ins->type);
1281         }
1282         return NULL;
1283 }
1284
1285 static G_GNUC_UNUSED int
1286 type_to_stack_type (MonoCompile *cfg, MonoType *t)
1287 {
1288         t = mono_type_get_underlying_type (t);
1289         switch (t->type) {
1290         case MONO_TYPE_I1:
1291         case MONO_TYPE_U1:
1292         case MONO_TYPE_I2:
1293         case MONO_TYPE_U2:
1294         case MONO_TYPE_I4:
1295         case MONO_TYPE_U4:
1296                 return STACK_I4;
1297         case MONO_TYPE_I:
1298         case MONO_TYPE_U:
1299         case MONO_TYPE_PTR:
1300         case MONO_TYPE_FNPTR:
1301                 return STACK_PTR;
1302         case MONO_TYPE_CLASS:
1303         case MONO_TYPE_STRING:
1304         case MONO_TYPE_OBJECT:
1305         case MONO_TYPE_SZARRAY:
1306         case MONO_TYPE_ARRAY:    
1307                 return STACK_OBJ;
1308         case MONO_TYPE_I8:
1309         case MONO_TYPE_U8:
1310                 return STACK_I8;
1311         case MONO_TYPE_R4:
1312                 return cfg->r4_stack_type;
1313         case MONO_TYPE_R8:
1314                 return STACK_R8;
1315         case MONO_TYPE_VALUETYPE:
1316         case MONO_TYPE_TYPEDBYREF:
1317                 return STACK_VTYPE;
1318         case MONO_TYPE_GENERICINST:
1319                 if (mono_type_generic_inst_is_valuetype (t))
1320                         return STACK_VTYPE;
1321                 else
1322                         return STACK_OBJ;
1323                 break;
1324         default:
1325                 g_assert_not_reached ();
1326         }
1327
1328         return -1;
1329 }
1330
1331 static MonoClass*
1332 array_access_to_klass (int opcode)
1333 {
1334         switch (opcode) {
1335         case CEE_LDELEM_U1:
1336                 return mono_defaults.byte_class;
1337         case CEE_LDELEM_U2:
1338                 return mono_defaults.uint16_class;
1339         case CEE_LDELEM_I:
1340         case CEE_STELEM_I:
1341                 return mono_defaults.int_class;
1342         case CEE_LDELEM_I1:
1343         case CEE_STELEM_I1:
1344                 return mono_defaults.sbyte_class;
1345         case CEE_LDELEM_I2:
1346         case CEE_STELEM_I2:
1347                 return mono_defaults.int16_class;
1348         case CEE_LDELEM_I4:
1349         case CEE_STELEM_I4:
1350                 return mono_defaults.int32_class;
1351         case CEE_LDELEM_U4:
1352                 return mono_defaults.uint32_class;
1353         case CEE_LDELEM_I8:
1354         case CEE_STELEM_I8:
1355                 return mono_defaults.int64_class;
1356         case CEE_LDELEM_R4:
1357         case CEE_STELEM_R4:
1358                 return mono_defaults.single_class;
1359         case CEE_LDELEM_R8:
1360         case CEE_STELEM_R8:
1361                 return mono_defaults.double_class;
1362         case CEE_LDELEM_REF:
1363         case CEE_STELEM_REF:
1364                 return mono_defaults.object_class;
1365         default:
1366                 g_assert_not_reached ();
1367         }
1368         return NULL;
1369 }
1370
1371 /*
1372  * We try to share variables when possible
1373  */
1374 static MonoInst *
1375 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1376 {
1377         MonoInst *res;
1378         int pos, vnum;
1379
1380         /* inlining can result in deeper stacks */ 
1381         if (slot >= cfg->header->max_stack)
1382                 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1383
1384         pos = ins->type - 1 + slot * STACK_MAX;
1385
1386         switch (ins->type) {
1387         case STACK_I4:
1388         case STACK_I8:
1389         case STACK_R8:
1390         case STACK_PTR:
1391         case STACK_MP:
1392         case STACK_OBJ:
1393                 if ((vnum = cfg->intvars [pos]))
1394                         return cfg->varinfo [vnum];
1395                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1396                 cfg->intvars [pos] = res->inst_c0;
1397                 break;
1398         default:
1399                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1400         }
1401         return res;
1402 }
1403
1404 static void
1405 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
1406 {
1407         /* 
1408          * Don't use this if a generic_context is set, since that means AOT can't
1409          * look up the method using just the image+token.
1410          * table == 0 means this is a reference made from a wrapper.
1411          */
1412         if (cfg->compile_aot && !cfg->generic_context && (mono_metadata_token_table (token) > 0)) {
1413                 MonoJumpInfoToken *jump_info_token = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
1414                 jump_info_token->image = image;
1415                 jump_info_token->token = token;
1416                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
1417         }
1418 }
1419
1420 /*
1421  * This function is called to handle items that are left on the evaluation stack
1422  * at basic block boundaries. What happens is that we save the values to local variables
1423  * and we reload them later when first entering the target basic block (with the
1424  * handle_loaded_temps () function).
1425  * A single joint point will use the same variables (stored in the array bb->out_stack or
1426  * bb->in_stack, if the basic block is before or after the joint point).
1427  *
1428  * This function needs to be called _before_ emitting the last instruction of
1429  * the bb (i.e. before emitting a branch).
1430  * If the stack merge fails at a join point, cfg->unverifiable is set.
1431  */
1432 static void
1433 handle_stack_args (MonoCompile *cfg, MonoInst **sp, int count)
1434 {
1435         int i, bindex;
1436         MonoBasicBlock *bb = cfg->cbb;
1437         MonoBasicBlock *outb;
1438         MonoInst *inst, **locals;
1439         gboolean found;
1440
1441         if (!count)
1442                 return;
1443         if (cfg->verbose_level > 3)
1444                 printf ("%d item(s) on exit from B%d\n", count, bb->block_num);
1445         if (!bb->out_scount) {
1446                 bb->out_scount = count;
1447                 //printf ("bblock %d has out:", bb->block_num);
1448                 found = FALSE;
1449                 for (i = 0; i < bb->out_count; ++i) {
1450                         outb = bb->out_bb [i];
1451                         /* exception handlers are linked, but they should not be considered for stack args */
1452                         if (outb->flags & BB_EXCEPTION_HANDLER)
1453                                 continue;
1454                         //printf (" %d", outb->block_num);
1455                         if (outb->in_stack) {
1456                                 found = TRUE;
1457                                 bb->out_stack = outb->in_stack;
1458                                 break;
1459                         }
1460                 }
1461                 //printf ("\n");
1462                 if (!found) {
1463                         bb->out_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1464                         for (i = 0; i < count; ++i) {
1465                                 /* 
1466                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
1467                                  * stack slot and if they are of the same type.
1468                                  * This won't cause conflicts since if 'local' is used to 
1469                                  * store one of the values in the in_stack of a bblock, then
1470                                  * the same variable will be used for the same outgoing stack 
1471                                  * slot as well. 
1472                                  * This doesn't work when inlining methods, since the bblocks
1473                                  * in the inlined methods do not inherit their in_stack from
1474                                  * the bblock they are inlined to. See bug #58863 for an
1475                                  * example.
1476                                  */
1477                                 if (cfg->inlined_method)
1478                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1479                                 else
1480                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1481                         }
1482                 }
1483         }
1484
1485         for (i = 0; i < bb->out_count; ++i) {
1486                 outb = bb->out_bb [i];
1487                 /* exception handlers are linked, but they should not be considered for stack args */
1488                 if (outb->flags & BB_EXCEPTION_HANDLER)
1489                         continue;
1490                 if (outb->in_scount) {
1491                         if (outb->in_scount != bb->out_scount) {
1492                                 cfg->unverifiable = TRUE;
1493                                 return;
1494                         }
1495                         continue; /* check they are the same locals */
1496                 }
1497                 outb->in_scount = count;
1498                 outb->in_stack = bb->out_stack;
1499         }
1500
1501         locals = bb->out_stack;
1502         cfg->cbb = bb;
1503         for (i = 0; i < count; ++i) {
1504                 EMIT_NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1505                 inst->cil_code = sp [i]->cil_code;
1506                 sp [i] = locals [i];
1507                 if (cfg->verbose_level > 3)
1508                         printf ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
1509         }
1510
1511         /*
1512          * It is possible that the out bblocks already have in_stack assigned, and
1513          * the in_stacks differ. In this case, we will store to all the different 
1514          * in_stacks.
1515          */
1516
1517         found = TRUE;
1518         bindex = 0;
1519         while (found) {
1520                 /* Find a bblock which has a different in_stack */
1521                 found = FALSE;
1522                 while (bindex < bb->out_count) {
1523                         outb = bb->out_bb [bindex];
1524                         /* exception handlers are linked, but they should not be considered for stack args */
1525                         if (outb->flags & BB_EXCEPTION_HANDLER) {
1526                                 bindex++;
1527                                 continue;
1528                         }
1529                         if (outb->in_stack != locals) {
1530                                 for (i = 0; i < count; ++i) {
1531                                         EMIT_NEW_TEMPSTORE (cfg, inst, outb->in_stack [i]->inst_c0, sp [i]);
1532                                         inst->cil_code = sp [i]->cil_code;
1533                                         sp [i] = locals [i];
1534                                         if (cfg->verbose_level > 3)
1535                                                 printf ("storing %d to temp %d\n", i, (int)outb->in_stack [i]->inst_c0);
1536                                 }
1537                                 locals = outb->in_stack;
1538                                 found = TRUE;
1539                                 break;
1540                         }
1541                         bindex ++;
1542                 }
1543         }
1544 }
1545
1546 /* Emit code which loads interface_offsets [klass->interface_id]
1547  * The array is stored in memory before vtable.
1548 */
1549 static void
1550 mini_emit_load_intf_reg_vtable (MonoCompile *cfg, int intf_reg, int vtable_reg, MonoClass *klass)
1551 {
1552         if (cfg->compile_aot) {
1553                 int ioffset_reg = alloc_preg (cfg);
1554                 int iid_reg = alloc_preg (cfg);
1555
1556                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_ADJUSTED_IID);
1557                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ioffset_reg, iid_reg, vtable_reg);
1558                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, intf_reg, ioffset_reg, 0);
1559         }
1560         else {
1561                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, intf_reg, vtable_reg, -((klass->interface_id + 1) * SIZEOF_VOID_P));
1562         }
1563 }
1564
1565 static void
1566 mini_emit_interface_bitmap_check (MonoCompile *cfg, int intf_bit_reg, int base_reg, int offset, MonoClass *klass)
1567 {
1568         int ibitmap_reg = alloc_preg (cfg);
1569 #ifdef COMPRESSED_INTERFACE_BITMAP
1570         MonoInst *args [2];
1571         MonoInst *res, *ins;
1572         NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, ibitmap_reg, base_reg, offset);
1573         MONO_ADD_INS (cfg->cbb, ins);
1574         args [0] = ins;
1575         if (cfg->compile_aot)
1576                 EMIT_NEW_AOTCONST (cfg, args [1], MONO_PATCH_INFO_IID, klass);
1577         else
1578                 EMIT_NEW_ICONST (cfg, args [1], klass->interface_id);
1579         res = mono_emit_jit_icall (cfg, mono_class_interface_match, args);
1580         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, intf_bit_reg, res->dreg);
1581 #else
1582         int ibitmap_byte_reg = alloc_preg (cfg);
1583
1584         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, base_reg, offset);
1585
1586         if (cfg->compile_aot) {
1587                 int iid_reg = alloc_preg (cfg);
1588                 int shifted_iid_reg = alloc_preg (cfg);
1589                 int ibitmap_byte_address_reg = alloc_preg (cfg);
1590                 int masked_iid_reg = alloc_preg (cfg);
1591                 int iid_one_bit_reg = alloc_preg (cfg);
1592                 int iid_bit_reg = alloc_preg (cfg);
1593                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1594                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, shifted_iid_reg, iid_reg, 3);
1595                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ibitmap_byte_address_reg, ibitmap_reg, shifted_iid_reg);
1596                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, ibitmap_byte_reg, ibitmap_byte_address_reg, 0);
1597                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, masked_iid_reg, iid_reg, 7);
1598                 MONO_EMIT_NEW_ICONST (cfg, iid_one_bit_reg, 1);
1599                 MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg);
1600                 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg);
1601         } else {
1602                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
1603                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
1604         }
1605 #endif
1606 }
1607
1608 /* 
1609  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
1610  * stored in "klass_reg" implements the interface "klass".
1611  */
1612 static void
1613 mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass)
1614 {
1615         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, interface_bitmap), klass);
1616 }
1617
1618 /* 
1619  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoVTable
1620  * stored in "vtable_reg" implements the interface "klass".
1621  */
1622 static void
1623 mini_emit_load_intf_bit_reg_vtable (MonoCompile *cfg, int intf_bit_reg, int vtable_reg, MonoClass *klass)
1624 {
1625         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, interface_bitmap), klass);
1626 }
1627
1628 /* 
1629  * Emit code which checks whenever the interface id of @klass is smaller than
1630  * than the value given by max_iid_reg.
1631 */
1632 static void
1633 mini_emit_max_iid_check (MonoCompile *cfg, int max_iid_reg, MonoClass *klass,
1634                                                  MonoBasicBlock *false_target)
1635 {
1636         if (cfg->compile_aot) {
1637                 int iid_reg = alloc_preg (cfg);
1638                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1639                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, max_iid_reg, iid_reg);
1640         }
1641         else
1642                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, max_iid_reg, klass->interface_id);
1643         if (false_target)
1644                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1645         else
1646                 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1647 }
1648
1649 /* Same as above, but obtains max_iid from a vtable */
1650 static void
1651 mini_emit_max_iid_check_vtable (MonoCompile *cfg, int vtable_reg, MonoClass *klass,
1652                                                                  MonoBasicBlock *false_target)
1653 {
1654         int max_iid_reg = alloc_preg (cfg);
1655                 
1656         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, max_interface_id));
1657         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1658 }
1659
1660 /* Same as above, but obtains max_iid from a klass */
1661 static void
1662 mini_emit_max_iid_check_class (MonoCompile *cfg, int klass_reg, MonoClass *klass,
1663                                                                  MonoBasicBlock *false_target)
1664 {
1665         int max_iid_reg = alloc_preg (cfg);
1666
1667         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, max_interface_id));
1668         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1669 }
1670
1671 static void
1672 mini_emit_isninst_cast_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_ins, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1673 {
1674         int idepth_reg = alloc_preg (cfg);
1675         int stypes_reg = alloc_preg (cfg);
1676         int stype = alloc_preg (cfg);
1677
1678         mono_class_setup_supertypes (klass);
1679
1680         if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1681                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1682                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1683                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1684         }
1685         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1686         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1687         if (klass_ins) {
1688                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, klass_ins->dreg);
1689         } else if (cfg->compile_aot) {
1690                 int const_reg = alloc_preg (cfg);
1691                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1692                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, const_reg);
1693         } else {
1694                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, stype, klass);
1695         }
1696         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, true_target);
1697 }
1698
1699 static void
1700 mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1701 {
1702         mini_emit_isninst_cast_inst (cfg, klass_reg, klass, NULL, false_target, true_target);
1703 }
1704
1705 static void
1706 mini_emit_iface_cast (MonoCompile *cfg, int vtable_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1707 {
1708         int intf_reg = alloc_preg (cfg);
1709
1710         mini_emit_max_iid_check_vtable (cfg, vtable_reg, klass, false_target);
1711         mini_emit_load_intf_bit_reg_vtable (cfg, intf_reg, vtable_reg, klass);
1712         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_reg, 0);
1713         if (true_target)
1714                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1715         else
1716                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");               
1717 }
1718
1719 /*
1720  * Variant of the above that takes a register to the class, not the vtable.
1721  */
1722 static void
1723 mini_emit_iface_class_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1724 {
1725         int intf_bit_reg = alloc_preg (cfg);
1726
1727         mini_emit_max_iid_check_class (cfg, klass_reg, klass, false_target);
1728         mini_emit_load_intf_bit_reg_class (cfg, intf_bit_reg, klass_reg, klass);
1729         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_bit_reg, 0);
1730         if (true_target)
1731                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1732         else
1733                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
1734 }
1735
1736 static inline void
1737 mini_emit_class_check_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_inst)
1738 {
1739         if (klass_inst) {
1740                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_inst->dreg);
1741         } else if (cfg->compile_aot) {
1742                 int const_reg = alloc_preg (cfg);
1743                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1744                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1745         } else {
1746                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1747         }
1748         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1749 }
1750
1751 static inline void
1752 mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
1753 {
1754         mini_emit_class_check_inst (cfg, klass_reg, klass, NULL);
1755 }
1756
1757 static inline void
1758 mini_emit_class_check_branch (MonoCompile *cfg, int klass_reg, MonoClass *klass, int branch_op, MonoBasicBlock *target)
1759 {
1760         if (cfg->compile_aot) {
1761                 int const_reg = alloc_preg (cfg);
1762                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1763                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1764         } else {
1765                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1766         }
1767         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, branch_op, target);
1768 }
1769
1770 static void
1771 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null);
1772         
1773 static void
1774 mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoInst *klass_inst, MonoBasicBlock *object_is_null)
1775 {
1776         if (klass->rank) {
1777                 int rank_reg = alloc_preg (cfg);
1778                 int eclass_reg = alloc_preg (cfg);
1779
1780                 g_assert (!klass_inst);
1781                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, rank));
1782                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
1783                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1784                 //              MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
1785                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
1786                 if (klass->cast_class == mono_defaults.object_class) {
1787                         int parent_reg = alloc_preg (cfg);
1788                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
1789                         mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, object_is_null);
1790                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1791                 } else if (klass->cast_class == mono_defaults.enum_class->parent) {
1792                         mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, object_is_null);
1793                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1794                 } else if (klass->cast_class == mono_defaults.enum_class) {
1795                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1796                 } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1797                         mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, NULL, NULL);
1798                 } else {
1799                         // Pass -1 as obj_reg to skip the check below for arrays of arrays
1800                         mini_emit_castclass (cfg, -1, eclass_reg, klass->cast_class, object_is_null);
1801                 }
1802
1803                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY) && (obj_reg != -1)) {
1804                         /* Check that the object is a vector too */
1805                         int bounds_reg = alloc_preg (cfg);
1806                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
1807                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
1808                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1809                 }
1810         } else {
1811                 int idepth_reg = alloc_preg (cfg);
1812                 int stypes_reg = alloc_preg (cfg);
1813                 int stype = alloc_preg (cfg);
1814
1815                 mono_class_setup_supertypes (klass);
1816
1817                 if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1818                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1819                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1820                         MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1821                 }
1822                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1823                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1824                 mini_emit_class_check_inst (cfg, stype, klass, klass_inst);
1825         }
1826 }
1827
1828 static void
1829 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null)
1830 {
1831         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, NULL, object_is_null);
1832 }
1833
1834 static void 
1835 mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
1836 {
1837         int val_reg;
1838
1839         g_assert (val == 0);
1840
1841         if (align == 0)
1842                 align = 4;
1843
1844         if ((size <= SIZEOF_REGISTER) && (size <= align)) {
1845                 switch (size) {
1846                 case 1:
1847                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, destreg, offset, val);
1848                         return;
1849                 case 2:
1850                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI2_MEMBASE_IMM, destreg, offset, val);
1851                         return;
1852                 case 4:
1853                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, destreg, offset, val);
1854                         return;
1855 #if SIZEOF_REGISTER == 8
1856                 case 8:
1857                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI8_MEMBASE_IMM, destreg, offset, val);
1858                         return;
1859 #endif
1860                 }
1861         }
1862
1863         val_reg = alloc_preg (cfg);
1864
1865         if (SIZEOF_REGISTER == 8)
1866                 MONO_EMIT_NEW_I8CONST (cfg, val_reg, val);
1867         else
1868                 MONO_EMIT_NEW_ICONST (cfg, val_reg, val);
1869
1870         if (align < 4) {
1871                 /* This could be optimized further if neccesary */
1872                 while (size >= 1) {
1873                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1874                         offset += 1;
1875                         size -= 1;
1876                 }
1877                 return;
1878         }       
1879
1880 #if !NO_UNALIGNED_ACCESS
1881         if (SIZEOF_REGISTER == 8) {
1882                 if (offset % 8) {
1883                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1884                         offset += 4;
1885                         size -= 4;
1886                 }
1887                 while (size >= 8) {
1888                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, offset, val_reg);
1889                         offset += 8;
1890                         size -= 8;
1891                 }
1892         }       
1893 #endif
1894
1895         while (size >= 4) {
1896                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1897                 offset += 4;
1898                 size -= 4;
1899         }
1900         while (size >= 2) {
1901                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg);
1902                 offset += 2;
1903                 size -= 2;
1904         }
1905         while (size >= 1) {
1906                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1907                 offset += 1;
1908                 size -= 1;
1909         }
1910 }
1911
1912 void 
1913 mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
1914 {
1915         int cur_reg;
1916
1917         if (align == 0)
1918                 align = 4;
1919
1920         /*FIXME arbitrary hack to avoid unbound code expansion.*/
1921         g_assert (size < 10000);
1922
1923         if (align < 4) {
1924                 /* This could be optimized further if neccesary */
1925                 while (size >= 1) {
1926                         cur_reg = alloc_preg (cfg);
1927                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1928                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1929                         doffset += 1;
1930                         soffset += 1;
1931                         size -= 1;
1932                 }
1933         }
1934
1935 #if !NO_UNALIGNED_ACCESS
1936         if (SIZEOF_REGISTER == 8) {
1937                 while (size >= 8) {
1938                         cur_reg = alloc_preg (cfg);
1939                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI8_MEMBASE, cur_reg, srcreg, soffset);
1940                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, doffset, cur_reg);
1941                         doffset += 8;
1942                         soffset += 8;
1943                         size -= 8;
1944                 }
1945         }       
1946 #endif
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, int 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                         EMIT_NEW_AOTCONST (cfg, args [0], MONO_PATCH_INFO_JIT_TLS_ID, NULL);
2056                         /* call pthread_getspecific () */
2057                         jit_tls_ins = mono_emit_jit_icall (cfg, pthread_getspecific, args);
2058                         /* lmf_addr = &jit_tls->lmf */
2059                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, cfg->lmf_addr_var->dreg, jit_tls_ins->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2060                         lmf_ins = ins;
2061 #else
2062                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2063 #endif
2064                 }
2065 #endif
2066                 lmf_ins->dreg = cfg->lmf_addr_var->dreg;
2067
2068                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2069                 lmf_reg = ins->dreg;
2070
2071                 prev_lmf_reg = alloc_preg (cfg);
2072                 /* Save previous_lmf */
2073                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, cfg->lmf_addr_var->dreg, 0);
2074                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), prev_lmf_reg);
2075                 /* Set new lmf */
2076                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, cfg->lmf_addr_var->dreg, 0, lmf_reg);
2077         }
2078 }
2079
2080 /*
2081  * emit_pop_lmf:
2082  *
2083  *   Emit IR to pop the current LMF from the LMF stack.
2084  */
2085 static void
2086 emit_pop_lmf (MonoCompile *cfg)
2087 {
2088         int lmf_reg, lmf_addr_reg, prev_lmf_reg;
2089         MonoInst *ins;
2090
2091         if (!cfg->lmf_ir)
2092                 return;
2093
2094         EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2095         lmf_reg = ins->dreg;
2096
2097         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
2098                 /* Load previous_lmf */
2099                 prev_lmf_reg = alloc_preg (cfg);
2100                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2101                 /* Set new LMF */
2102                 emit_tls_set (cfg, prev_lmf_reg, TLS_KEY_LMF);
2103         } else {
2104                 /*
2105                  * Emit IR to pop the LMF:
2106                  * *(lmf->lmf_addr) = lmf->prev_lmf
2107                  */
2108                 /* This could be called before emit_push_lmf () */
2109                 if (!cfg->lmf_addr_var)
2110                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2111                 lmf_addr_reg = cfg->lmf_addr_var->dreg;
2112
2113                 prev_lmf_reg = alloc_preg (cfg);
2114                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2115                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, prev_lmf_reg);
2116         }
2117 }
2118
2119 static void
2120 emit_instrumentation_call (MonoCompile *cfg, void *func)
2121 {
2122         MonoInst *iargs [1];
2123
2124         /*
2125          * Avoid instrumenting inlined methods since it can
2126          * distort profiling results.
2127          */
2128         if (cfg->method != cfg->current_method)
2129                 return;
2130
2131         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
2132                 EMIT_NEW_METHODCONST (cfg, iargs [0], cfg->method);
2133                 mono_emit_jit_icall (cfg, func, iargs);
2134         }
2135 }
2136
2137 static int
2138 ret_type_to_call_opcode (MonoCompile *cfg, MonoType *type, int calli, int virt, MonoGenericSharingContext *gsctx)
2139 {
2140 handle_enum:
2141         type = mini_get_underlying_type (cfg, type);
2142         switch (type->type) {
2143         case MONO_TYPE_VOID:
2144                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALL_MEMBASE: OP_VOIDCALL;
2145         case MONO_TYPE_I1:
2146         case MONO_TYPE_U1:
2147         case MONO_TYPE_I2:
2148         case MONO_TYPE_U2:
2149         case MONO_TYPE_I4:
2150         case MONO_TYPE_U4:
2151                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2152         case MONO_TYPE_I:
2153         case MONO_TYPE_U:
2154         case MONO_TYPE_PTR:
2155         case MONO_TYPE_FNPTR:
2156                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2157         case MONO_TYPE_CLASS:
2158         case MONO_TYPE_STRING:
2159         case MONO_TYPE_OBJECT:
2160         case MONO_TYPE_SZARRAY:
2161         case MONO_TYPE_ARRAY:    
2162                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2163         case MONO_TYPE_I8:
2164         case MONO_TYPE_U8:
2165                 return calli? OP_LCALL_REG: virt? OP_LCALL_MEMBASE: OP_LCALL;
2166         case MONO_TYPE_R4:
2167                 if (cfg->r4fp)
2168                         return calli? OP_RCALL_REG: virt? OP_RCALL_MEMBASE: OP_RCALL;
2169                 else
2170                         return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2171         case MONO_TYPE_R8:
2172                 return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2173         case MONO_TYPE_VALUETYPE:
2174                 if (type->data.klass->enumtype) {
2175                         type = mono_class_enum_basetype (type->data.klass);
2176                         goto handle_enum;
2177                 } else
2178                         return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2179         case MONO_TYPE_TYPEDBYREF:
2180                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2181         case MONO_TYPE_GENERICINST:
2182                 type = &type->data.generic_class->container_class->byval_arg;
2183                 goto handle_enum;
2184         case MONO_TYPE_VAR:
2185         case MONO_TYPE_MVAR:
2186                 /* gsharedvt */
2187                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2188         default:
2189                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
2190         }
2191         return -1;
2192 }
2193
2194 /*
2195  * target_type_is_incompatible:
2196  * @cfg: MonoCompile context
2197  *
2198  * Check that the item @arg on the evaluation stack can be stored
2199  * in the target type (can be a local, or field, etc).
2200  * The cfg arg can be used to check if we need verification or just
2201  * validity checks.
2202  *
2203  * Returns: non-0 value if arg can't be stored on a target.
2204  */
2205 static int
2206 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
2207 {
2208         MonoType *simple_type;
2209         MonoClass *klass;
2210
2211         if (target->byref) {
2212                 /* FIXME: check that the pointed to types match */
2213                 if (arg->type == STACK_MP)
2214                         return arg->klass != mono_class_from_mono_type (target);
2215                 if (arg->type == STACK_PTR)
2216                         return 0;
2217                 return 1;
2218         }
2219
2220         simple_type = mini_get_underlying_type (cfg, target);
2221         switch (simple_type->type) {
2222         case MONO_TYPE_VOID:
2223                 return 1;
2224         case MONO_TYPE_I1:
2225         case MONO_TYPE_U1:
2226         case MONO_TYPE_I2:
2227         case MONO_TYPE_U2:
2228         case MONO_TYPE_I4:
2229         case MONO_TYPE_U4:
2230                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2231                         return 1;
2232                 return 0;
2233         case MONO_TYPE_PTR:
2234                 /* STACK_MP is needed when setting pinned locals */
2235                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2236                         return 1;
2237                 return 0;
2238         case MONO_TYPE_I:
2239         case MONO_TYPE_U:
2240         case MONO_TYPE_FNPTR:
2241                 /* 
2242                  * Some opcodes like ldloca returns 'transient pointers' which can be stored in
2243                  * in native int. (#688008).
2244                  */
2245                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2246                         return 1;
2247                 return 0;
2248         case MONO_TYPE_CLASS:
2249         case MONO_TYPE_STRING:
2250         case MONO_TYPE_OBJECT:
2251         case MONO_TYPE_SZARRAY:
2252         case MONO_TYPE_ARRAY:    
2253                 if (arg->type != STACK_OBJ)
2254                         return 1;
2255                 /* FIXME: check type compatibility */
2256                 return 0;
2257         case MONO_TYPE_I8:
2258         case MONO_TYPE_U8:
2259                 if (arg->type != STACK_I8)
2260                         return 1;
2261                 return 0;
2262         case MONO_TYPE_R4:
2263                 if (arg->type != cfg->r4_stack_type)
2264                         return 1;
2265                 return 0;
2266         case MONO_TYPE_R8:
2267                 if (arg->type != STACK_R8)
2268                         return 1;
2269                 return 0;
2270         case MONO_TYPE_VALUETYPE:
2271                 if (arg->type != STACK_VTYPE)
2272                         return 1;
2273                 klass = mono_class_from_mono_type (simple_type);
2274                 if (klass != arg->klass)
2275                         return 1;
2276                 return 0;
2277         case MONO_TYPE_TYPEDBYREF:
2278                 if (arg->type != STACK_VTYPE)
2279                         return 1;
2280                 klass = mono_class_from_mono_type (simple_type);
2281                 if (klass != arg->klass)
2282                         return 1;
2283                 return 0;
2284         case MONO_TYPE_GENERICINST:
2285                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2286                         if (arg->type != STACK_VTYPE)
2287                                 return 1;
2288                         klass = mono_class_from_mono_type (simple_type);
2289                         if (klass != arg->klass)
2290                                 return 1;
2291                         return 0;
2292                 } else {
2293                         if (arg->type != STACK_OBJ)
2294                                 return 1;
2295                         /* FIXME: check type compatibility */
2296                         return 0;
2297                 }
2298         case MONO_TYPE_VAR:
2299         case MONO_TYPE_MVAR:
2300                 g_assert (cfg->generic_sharing_context);
2301                 if (mini_type_var_is_vt (cfg, simple_type)) {
2302                         if (arg->type != STACK_VTYPE)
2303                                 return 1;
2304                 } else {
2305                         if (arg->type != STACK_OBJ)
2306                                 return 1;
2307                 }
2308                 return 0;
2309         default:
2310                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2311         }
2312         return 1;
2313 }
2314
2315 /*
2316  * Prepare arguments for passing to a function call.
2317  * Return a non-zero value if the arguments can't be passed to the given
2318  * signature.
2319  * The type checks are not yet complete and some conversions may need
2320  * casts on 32 or 64 bit architectures.
2321  *
2322  * FIXME: implement this using target_type_is_incompatible ()
2323  */
2324 static int
2325 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2326 {
2327         MonoType *simple_type;
2328         int i;
2329
2330         if (sig->hasthis) {
2331                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2332                         return 1;
2333                 args++;
2334         }
2335         for (i = 0; i < sig->param_count; ++i) {
2336                 if (sig->params [i]->byref) {
2337                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2338                                 return 1;
2339                         continue;
2340                 }
2341                 simple_type = mini_get_underlying_type (cfg, sig->params [i]);
2342 handle_enum:
2343                 switch (simple_type->type) {
2344                 case MONO_TYPE_VOID:
2345                         return 1;
2346                         continue;
2347                 case MONO_TYPE_I1:
2348                 case MONO_TYPE_U1:
2349                 case MONO_TYPE_I2:
2350                 case MONO_TYPE_U2:
2351                 case MONO_TYPE_I4:
2352                 case MONO_TYPE_U4:
2353                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2354                                 return 1;
2355                         continue;
2356                 case MONO_TYPE_I:
2357                 case MONO_TYPE_U:
2358                 case MONO_TYPE_PTR:
2359                 case MONO_TYPE_FNPTR:
2360                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2361                                 return 1;
2362                         continue;
2363                 case MONO_TYPE_CLASS:
2364                 case MONO_TYPE_STRING:
2365                 case MONO_TYPE_OBJECT:
2366                 case MONO_TYPE_SZARRAY:
2367                 case MONO_TYPE_ARRAY:    
2368                         if (args [i]->type != STACK_OBJ)
2369                                 return 1;
2370                         continue;
2371                 case MONO_TYPE_I8:
2372                 case MONO_TYPE_U8:
2373                         if (args [i]->type != STACK_I8)
2374                                 return 1;
2375                         continue;
2376                 case MONO_TYPE_R4:
2377                         if (args [i]->type != cfg->r4_stack_type)
2378                                 return 1;
2379                         continue;
2380                 case MONO_TYPE_R8:
2381                         if (args [i]->type != STACK_R8)
2382                                 return 1;
2383                         continue;
2384                 case MONO_TYPE_VALUETYPE:
2385                         if (simple_type->data.klass->enumtype) {
2386                                 simple_type = mono_class_enum_basetype (simple_type->data.klass);
2387                                 goto handle_enum;
2388                         }
2389                         if (args [i]->type != STACK_VTYPE)
2390                                 return 1;
2391                         continue;
2392                 case MONO_TYPE_TYPEDBYREF:
2393                         if (args [i]->type != STACK_VTYPE)
2394                                 return 1;
2395                         continue;
2396                 case MONO_TYPE_GENERICINST:
2397                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2398                         goto handle_enum;
2399                 case MONO_TYPE_VAR:
2400                 case MONO_TYPE_MVAR:
2401                         /* gsharedvt */
2402                         if (args [i]->type != STACK_VTYPE)
2403                                 return 1;
2404                         continue;
2405                 default:
2406                         g_error ("unknown type 0x%02x in check_call_signature",
2407                                  simple_type->type);
2408                 }
2409         }
2410         return 0;
2411 }
2412
2413 static int
2414 callvirt_to_call (int opcode)
2415 {
2416         switch (opcode) {
2417         case OP_CALL_MEMBASE:
2418                 return OP_CALL;
2419         case OP_VOIDCALL_MEMBASE:
2420                 return OP_VOIDCALL;
2421         case OP_FCALL_MEMBASE:
2422                 return OP_FCALL;
2423         case OP_RCALL_MEMBASE:
2424                 return OP_RCALL;
2425         case OP_VCALL_MEMBASE:
2426                 return OP_VCALL;
2427         case OP_LCALL_MEMBASE:
2428                 return OP_LCALL;
2429         default:
2430                 g_assert_not_reached ();
2431         }
2432
2433         return -1;
2434 }
2435
2436 /* Either METHOD or IMT_ARG needs to be set */
2437 static void
2438 emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoMethod *method, MonoInst *imt_arg)
2439 {
2440         int method_reg;
2441
2442         if (COMPILE_LLVM (cfg)) {
2443                 method_reg = alloc_preg (cfg);
2444
2445                 if (imt_arg) {
2446                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2447                 } else if (cfg->compile_aot) {
2448                         MONO_EMIT_NEW_AOTCONST (cfg, method_reg, method, MONO_PATCH_INFO_METHODCONST);
2449                 } else {
2450                         MonoInst *ins;
2451                         MONO_INST_NEW (cfg, ins, OP_PCONST);
2452                         ins->inst_p0 = method;
2453                         ins->dreg = method_reg;
2454                         MONO_ADD_INS (cfg->cbb, ins);
2455                 }
2456
2457 #ifdef ENABLE_LLVM
2458                 call->imt_arg_reg = method_reg;
2459 #endif
2460 #ifdef MONO_ARCH_IMT_REG
2461         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2462 #else
2463         /* Need this to keep the IMT arg alive */
2464         mono_call_inst_add_outarg_reg (cfg, call, method_reg, 0, FALSE);
2465 #endif
2466                 return;
2467         }
2468
2469 #ifdef MONO_ARCH_IMT_REG
2470         method_reg = alloc_preg (cfg);
2471
2472         if (imt_arg) {
2473                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2474         } else if (cfg->compile_aot) {
2475                 MONO_EMIT_NEW_AOTCONST (cfg, method_reg, method, MONO_PATCH_INFO_METHODCONST);
2476         } else {
2477                 MonoInst *ins;
2478                 MONO_INST_NEW (cfg, ins, OP_PCONST);
2479                 ins->inst_p0 = method;
2480                 ins->dreg = method_reg;
2481                 MONO_ADD_INS (cfg->cbb, ins);
2482         }
2483
2484         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2485 #else
2486         mono_arch_emit_imt_argument (cfg, call, imt_arg);
2487 #endif
2488 }
2489
2490 static MonoJumpInfo *
2491 mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpointer target)
2492 {
2493         MonoJumpInfo *ji = mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
2494
2495         ji->ip.i = ip;
2496         ji->type = type;
2497         ji->data.target = target;
2498
2499         return ji;
2500 }
2501
2502 static int
2503 mini_class_check_context_used (MonoCompile *cfg, MonoClass *klass)
2504 {
2505         if (cfg->generic_sharing_context)
2506                 return mono_class_check_context_used (klass);
2507         else
2508                 return 0;
2509 }
2510
2511 static int
2512 mini_method_check_context_used (MonoCompile *cfg, MonoMethod *method)
2513 {
2514         if (cfg->generic_sharing_context)
2515                 return mono_method_check_context_used (method);
2516         else
2517                 return 0;
2518 }
2519
2520 /*
2521  * check_method_sharing:
2522  *
2523  *   Check whenever the vtable or an mrgctx needs to be passed when calling CMETHOD.
2524  */
2525 static void
2526 check_method_sharing (MonoCompile *cfg, MonoMethod *cmethod, gboolean *out_pass_vtable, gboolean *out_pass_mrgctx)
2527 {
2528         gboolean pass_vtable = FALSE;
2529         gboolean pass_mrgctx = FALSE;
2530
2531         if (((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
2532                 (cmethod->klass->generic_class || cmethod->klass->generic_container)) {
2533                 gboolean sharable = FALSE;
2534
2535                 if (mono_method_is_generic_sharable (cmethod, TRUE)) {
2536                         sharable = TRUE;
2537                 } else {
2538                         gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
2539                         MonoGenericContext *context = mini_class_get_context (cmethod->klass);
2540                         gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
2541
2542                         sharable = sharing_enabled && context_sharable;
2543                 }
2544
2545                 /*
2546                  * Pass vtable iff target method might
2547                  * be shared, which means that sharing
2548                  * is enabled for its class and its
2549                  * context is sharable (and it's not a
2550                  * generic method).
2551                  */
2552                 if (sharable && !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
2553                         pass_vtable = TRUE;
2554         }
2555
2556         if (mini_method_get_context (cmethod) &&
2557                 mini_method_get_context (cmethod)->method_inst) {
2558                 g_assert (!pass_vtable);
2559
2560                 if (mono_method_is_generic_sharable (cmethod, TRUE)) {
2561                         pass_mrgctx = TRUE;
2562                 } else {
2563                         gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
2564                         MonoGenericContext *context = mini_method_get_context (cmethod);
2565                         gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
2566
2567                         if (sharing_enabled && context_sharable)
2568                                 pass_mrgctx = TRUE;
2569                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, mono_method_signature (cmethod)))
2570                                 pass_mrgctx = TRUE;
2571                 }
2572         }
2573
2574         if (out_pass_vtable)
2575                 *out_pass_vtable = pass_vtable;
2576         if (out_pass_mrgctx)
2577                 *out_pass_mrgctx = pass_mrgctx;
2578 }
2579
2580 inline static MonoCallInst *
2581 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
2582                                          MonoInst **args, int calli, int virtual, int tail, int rgctx, int unbox_trampoline)
2583 {
2584         MonoType *sig_ret;
2585         MonoCallInst *call;
2586 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2587         int i;
2588 #endif
2589
2590         if (tail) {
2591                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
2592
2593                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
2594         } else
2595                 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (cfg, sig->ret, calli, virtual, cfg->generic_sharing_context));
2596
2597         call->args = args;
2598         call->signature = sig;
2599         call->rgctx_reg = rgctx;
2600         sig_ret = mini_get_underlying_type (cfg, sig->ret);
2601
2602         type_to_eval_stack_type ((cfg), sig_ret, &call->inst);
2603
2604         if (tail) {
2605                 if (mini_type_is_vtype (cfg, sig_ret)) {
2606                         call->vret_var = cfg->vret_addr;
2607                         //g_assert_not_reached ();
2608                 }
2609         } else if (mini_type_is_vtype (cfg, sig_ret)) {
2610                 MonoInst *temp = mono_compile_create_var (cfg, sig_ret, OP_LOCAL);
2611                 MonoInst *loada;
2612
2613                 temp->backend.is_pinvoke = sig->pinvoke;
2614
2615                 /*
2616                  * We use a new opcode OP_OUTARG_VTRETADDR instead of LDADDR for emitting the
2617                  * address of return value to increase optimization opportunities.
2618                  * Before vtype decomposition, the dreg of the call ins itself represents the
2619                  * fact the call modifies the return value. After decomposition, the call will
2620                  * be transformed into one of the OP_VOIDCALL opcodes, and the VTRETADDR opcode
2621                  * will be transformed into an LDADDR.
2622                  */
2623                 MONO_INST_NEW (cfg, loada, OP_OUTARG_VTRETADDR);
2624                 loada->dreg = alloc_preg (cfg);
2625                 loada->inst_p0 = temp;
2626                 /* We reference the call too since call->dreg could change during optimization */
2627                 loada->inst_p1 = call;
2628                 MONO_ADD_INS (cfg->cbb, loada);
2629
2630                 call->inst.dreg = temp->dreg;
2631
2632                 call->vret_var = loada;
2633         } else if (!MONO_TYPE_IS_VOID (sig_ret))
2634                 call->inst.dreg = alloc_dreg (cfg, call->inst.type);
2635
2636 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2637         if (COMPILE_SOFT_FLOAT (cfg)) {
2638                 /* 
2639                  * If the call has a float argument, we would need to do an r8->r4 conversion using 
2640                  * an icall, but that cannot be done during the call sequence since it would clobber
2641                  * the call registers + the stack. So we do it before emitting the call.
2642                  */
2643                 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2644                         MonoType *t;
2645                         MonoInst *in = call->args [i];
2646
2647                         if (i >= sig->hasthis)
2648                                 t = sig->params [i - sig->hasthis];
2649                         else
2650                                 t = &mono_defaults.int_class->byval_arg;
2651                         t = mono_type_get_underlying_type (t);
2652
2653                         if (!t->byref && t->type == MONO_TYPE_R4) {
2654                                 MonoInst *iargs [1];
2655                                 MonoInst *conv;
2656
2657                                 iargs [0] = in;
2658                                 conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
2659
2660                                 /* The result will be in an int vreg */
2661                                 call->args [i] = conv;
2662                         }
2663                 }
2664         }
2665 #endif
2666
2667         call->need_unbox_trampoline = unbox_trampoline;
2668
2669 #ifdef ENABLE_LLVM
2670         if (COMPILE_LLVM (cfg))
2671                 mono_llvm_emit_call (cfg, call);
2672         else
2673                 mono_arch_emit_call (cfg, call);
2674 #else
2675         mono_arch_emit_call (cfg, call);
2676 #endif
2677
2678         cfg->param_area = MAX (cfg->param_area, call->stack_usage);
2679         cfg->flags |= MONO_CFG_HAS_CALLS;
2680         
2681         return call;
2682 }
2683
2684 static void
2685 set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rgctx_arg)
2686 {
2687 #ifdef MONO_ARCH_RGCTX_REG
2688         mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
2689         cfg->uses_rgctx_reg = TRUE;
2690         call->rgctx_reg = TRUE;
2691 #ifdef ENABLE_LLVM
2692         call->rgctx_arg_reg = rgctx_reg;
2693 #endif
2694 #else
2695         NOT_IMPLEMENTED;
2696 #endif
2697 }       
2698
2699 inline static MonoInst*
2700 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg)
2701 {
2702         MonoCallInst *call;
2703         MonoInst *ins;
2704         int rgctx_reg = -1;
2705         gboolean check_sp = FALSE;
2706
2707         if (cfg->check_pinvoke_callconv && cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
2708                 WrapperInfo *info = mono_marshal_get_wrapper_info (cfg->method);
2709
2710                 if (info && info->subtype == WRAPPER_SUBTYPE_PINVOKE)
2711                         check_sp = TRUE;
2712         }
2713
2714         if (rgctx_arg) {
2715                 rgctx_reg = mono_alloc_preg (cfg);
2716                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2717         }
2718
2719         if (check_sp) {
2720                 if (!cfg->stack_inbalance_var)
2721                         cfg->stack_inbalance_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2722
2723                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2724                 ins->dreg = cfg->stack_inbalance_var->dreg;
2725                 MONO_ADD_INS (cfg->cbb, ins);
2726         }
2727
2728         call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE);
2729
2730         call->inst.sreg1 = addr->dreg;
2731
2732         if (imt_arg)
2733                 emit_imt_argument (cfg, call, NULL, imt_arg);
2734
2735         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2736
2737         if (check_sp) {
2738                 int sp_reg;
2739
2740                 sp_reg = mono_alloc_preg (cfg);
2741
2742                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2743                 ins->dreg = sp_reg;
2744                 MONO_ADD_INS (cfg->cbb, ins);
2745
2746                 /* Restore the stack so we don't crash when throwing the exception */
2747                 MONO_INST_NEW (cfg, ins, OP_SET_SP);
2748                 ins->sreg1 = cfg->stack_inbalance_var->dreg;
2749                 MONO_ADD_INS (cfg->cbb, ins);
2750
2751                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, cfg->stack_inbalance_var->dreg, sp_reg);
2752                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ExecutionEngineException");
2753         }
2754
2755         if (rgctx_arg)
2756                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2757
2758         return (MonoInst*)call;
2759 }
2760
2761 static MonoInst*
2762 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2763
2764 static MonoInst*
2765 emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type);
2766 static MonoInst*
2767 emit_get_rgctx_klass (MonoCompile *cfg, int context_used, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2768
2769 static MonoInst*
2770 mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig, gboolean tail,
2771                                                         MonoInst **args, MonoInst *this, MonoInst *imt_arg, MonoInst *rgctx_arg)
2772 {
2773 #ifndef DISABLE_REMOTING
2774         gboolean might_be_remote = FALSE;
2775 #endif
2776         gboolean virtual = this != NULL;
2777         gboolean enable_for_aot = TRUE;
2778         int context_used;
2779         MonoCallInst *call;
2780         int rgctx_reg = 0;
2781         gboolean need_unbox_trampoline;
2782
2783         if (!sig)
2784                 sig = mono_method_signature (method);
2785
2786         if (rgctx_arg) {
2787                 rgctx_reg = mono_alloc_preg (cfg);
2788                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2789         }
2790
2791         if (method->string_ctor) {
2792                 /* Create the real signature */
2793                 /* FIXME: Cache these */
2794                 MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_mempool (cfg->mempool, sig);
2795                 ctor_sig->ret = &mono_defaults.string_class->byval_arg;
2796
2797                 sig = ctor_sig;
2798         }
2799
2800         context_used = mini_method_check_context_used (cfg, method);
2801
2802 #ifndef DISABLE_REMOTING
2803         might_be_remote = this && sig->hasthis &&
2804                 (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) &&
2805                 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && (!MONO_CHECK_THIS (this) || context_used);
2806
2807         if (might_be_remote && context_used) {
2808                 MonoInst *addr;
2809
2810                 g_assert (cfg->generic_sharing_context);
2811
2812                 addr = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK);
2813
2814                 return mono_emit_calli (cfg, sig, args, addr, NULL, NULL);
2815         }
2816 #endif
2817
2818         need_unbox_trampoline = method->klass == mono_defaults.object_class || (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
2819
2820         call = mono_emit_call_args (cfg, sig, args, FALSE, virtual, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline);
2821
2822 #ifndef DISABLE_REMOTING
2823         if (might_be_remote)
2824                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2825         else
2826 #endif
2827                 call->method = method;
2828         call->inst.flags |= MONO_INST_HAS_METHOD;
2829         call->inst.inst_left = this;
2830         call->tail_call = tail;
2831
2832         if (virtual) {
2833                 int vtable_reg, slot_reg, this_reg;
2834                 int offset;
2835
2836                 this_reg = this->dreg;
2837
2838                 if (ARCH_HAVE_DELEGATE_TRAMPOLINES && (method->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (method->name, "Invoke")) {
2839                         MonoInst *dummy_use;
2840
2841                         MONO_EMIT_NULL_CHECK (cfg, this_reg);
2842
2843                         /* Make a call to delegate->invoke_impl */
2844                         call->inst.inst_basereg = this_reg;
2845                         call->inst.inst_offset = MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl);
2846                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2847
2848                         /* We must emit a dummy use here because the delegate trampoline will
2849                         replace the 'this' argument with the delegate target making this activation
2850                         no longer a root for the delegate.
2851                         This is an issue for delegates that target collectible code such as dynamic
2852                         methods of GC'able assemblies.
2853
2854                         For a test case look into #667921.
2855
2856                         FIXME: a dummy use is not the best way to do it as the local register allocator
2857                         will put it on a caller save register and spil it around the call. 
2858                         Ideally, we would either put it on a callee save register or only do the store part.  
2859                          */
2860                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [0]);
2861
2862                         return (MonoInst*)call;
2863                 }
2864
2865                 if ((!cfg->compile_aot || enable_for_aot) && 
2866                         (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
2867                          (MONO_METHOD_IS_FINAL (method) &&
2868                           method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)) &&
2869                         !(mono_class_is_marshalbyref (method->klass) && context_used)) {
2870                         /* 
2871                          * the method is not virtual, we just need to ensure this is not null
2872                          * and then we can call the method directly.
2873                          */
2874 #ifndef DISABLE_REMOTING
2875                         if (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) {
2876                                 /* 
2877                                  * The check above ensures method is not gshared, this is needed since
2878                                  * gshared methods can't have wrappers.
2879                                  */
2880                                 method = call->method = mono_marshal_get_remoting_invoke_with_check (method);
2881                         }
2882 #endif
2883
2884                         if (!method->string_ctor)
2885                                 MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2886
2887                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2888                 } else if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && MONO_METHOD_IS_FINAL (method)) {
2889                         /*
2890                          * the method is virtual, but we can statically dispatch since either
2891                          * it's class or the method itself are sealed.
2892                          * But first we need to ensure it's not a null reference.
2893                          */
2894                         MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2895
2896                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2897                 } else {
2898                         vtable_reg = alloc_preg (cfg);
2899                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2900                         if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2901                                 guint32 imt_slot = mono_method_get_imt_slot (method);
2902                                 emit_imt_argument (cfg, call, call->method, imt_arg);
2903                                 slot_reg = vtable_reg;
2904                                 offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
2905                         } else {
2906                                 slot_reg = vtable_reg;
2907                                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) +
2908                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
2909                                 if (imt_arg) {
2910                                         g_assert (mono_method_signature (method)->generic_param_count);
2911                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2912                                 }
2913                         }
2914
2915                         call->inst.sreg1 = slot_reg;
2916                         call->inst.inst_offset = offset;
2917                         call->virtual = TRUE;
2918                 }
2919         }
2920
2921         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2922
2923         if (rgctx_arg)
2924                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2925
2926         return (MonoInst*)call;
2927 }
2928
2929 MonoInst*
2930 mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this)
2931 {
2932         return mono_emit_method_call_full (cfg, method, mono_method_signature (method), FALSE, args, this, NULL, NULL);
2933 }
2934
2935 MonoInst*
2936 mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig,
2937                                            MonoInst **args)
2938 {
2939         MonoCallInst *call;
2940
2941         g_assert (sig);
2942
2943         call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE, FALSE, FALSE);
2944         call->fptr = func;
2945
2946         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2947
2948         return (MonoInst*)call;
2949 }
2950
2951 MonoInst*
2952 mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args)
2953 {
2954         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2955
2956         g_assert (info);
2957
2958         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2959 }
2960
2961 /*
2962  * mono_emit_abs_call:
2963  *
2964  *   Emit a call to the runtime function described by PATCH_TYPE and DATA.
2965  */
2966 inline static MonoInst*
2967 mono_emit_abs_call (MonoCompile *cfg, MonoJumpInfoType patch_type, gconstpointer data, 
2968                                         MonoMethodSignature *sig, MonoInst **args)
2969 {
2970         MonoJumpInfo *ji = mono_patch_info_new (cfg->mempool, 0, patch_type, data);
2971         MonoInst *ins;
2972
2973         /* 
2974          * We pass ji as the call address, the PATCH_INFO_ABS resolving code will
2975          * handle it.
2976          */
2977         if (cfg->abs_patches == NULL)
2978                 cfg->abs_patches = g_hash_table_new (NULL, NULL);
2979         g_hash_table_insert (cfg->abs_patches, ji, ji);
2980         ins = mono_emit_native_call (cfg, ji, sig, args);
2981         ((MonoCallInst*)ins)->fptr_is_patch = TRUE;
2982         return ins;
2983 }
2984
2985 static gboolean
2986 direct_icalls_enabled (MonoCompile *cfg)
2987 {
2988         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
2989 #ifdef TARGET_AMD64
2990         if (cfg->compile_llvm)
2991                 return FALSE;
2992 #endif
2993         if (cfg->gen_sdb_seq_points || cfg->disable_direct_icalls)
2994                 return FALSE;
2995         return TRUE;
2996 }
2997
2998 MonoInst*
2999 mono_emit_jit_icall_by_info (MonoCompile *cfg, MonoJitICallInfo *info, MonoInst **args, MonoBasicBlock **out_cbb)
3000 {
3001         /*
3002          * Call the jit icall without a wrapper if possible.
3003          * The wrapper is needed for the following reasons:
3004          * - to handle exceptions thrown using mono_raise_exceptions () from the
3005          *   icall function. The EH code needs the lmf frame pushed by the
3006          *   wrapper to be able to unwind back to managed code.
3007          * - to be able to do stack walks for asynchronously suspended
3008          *   threads when debugging.
3009          */
3010         if (info->no_raise && direct_icalls_enabled (cfg)) {
3011                 char *name;
3012                 int costs;
3013
3014                 if (!info->wrapper_method) {
3015                         name = g_strdup_printf ("__icall_wrapper_%s", info->name);
3016                         info->wrapper_method = mono_marshal_get_icall_wrapper (info->sig, name, info->func, TRUE);
3017                         g_free (name);
3018                         mono_memory_barrier ();
3019                 }
3020
3021                 /*
3022                  * Inline the wrapper method, which is basically a call to the C icall, and
3023                  * an exception check.
3024                  */
3025                 costs = inline_method (cfg, info->wrapper_method, NULL,
3026                                                            args, NULL, cfg->real_offset, TRUE, out_cbb);
3027                 g_assert (costs > 0);
3028                 g_assert (!MONO_TYPE_IS_VOID (info->sig->ret));
3029
3030                 return args [0];
3031         } else {
3032                 return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
3033         }
3034 }
3035  
3036 static MonoInst*
3037 mono_emit_widen_call_res (MonoCompile *cfg, MonoInst *ins, MonoMethodSignature *fsig)
3038 {
3039         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
3040                 if ((fsig->pinvoke || LLVM_ENABLED) && !fsig->ret->byref) {
3041                         int widen_op = -1;
3042
3043                         /* 
3044                          * Native code might return non register sized integers 
3045                          * without initializing the upper bits.
3046                          */
3047                         switch (mono_type_to_load_membase (cfg, fsig->ret)) {
3048                         case OP_LOADI1_MEMBASE:
3049                                 widen_op = OP_ICONV_TO_I1;
3050                                 break;
3051                         case OP_LOADU1_MEMBASE:
3052                                 widen_op = OP_ICONV_TO_U1;
3053                                 break;
3054                         case OP_LOADI2_MEMBASE:
3055                                 widen_op = OP_ICONV_TO_I2;
3056                                 break;
3057                         case OP_LOADU2_MEMBASE:
3058                                 widen_op = OP_ICONV_TO_U2;
3059                                 break;
3060                         default:
3061                                 break;
3062                         }
3063
3064                         if (widen_op != -1) {
3065                                 int dreg = alloc_preg (cfg);
3066                                 MonoInst *widen;
3067
3068                                 EMIT_NEW_UNALU (cfg, widen, widen_op, dreg, ins->dreg);
3069                                 widen->type = ins->type;
3070                                 ins = widen;
3071                         }
3072                 }
3073         }
3074
3075         return ins;
3076 }
3077
3078 static MonoMethod*
3079 get_memcpy_method (void)
3080 {
3081         static MonoMethod *memcpy_method = NULL;
3082         if (!memcpy_method) {
3083                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
3084                 if (!memcpy_method)
3085                         g_error ("Old corlib found. Install a new one");
3086         }
3087         return memcpy_method;
3088 }
3089
3090 static void
3091 create_write_barrier_bitmap (MonoCompile *cfg, MonoClass *klass, unsigned *wb_bitmap, int offset)
3092 {
3093         MonoClassField *field;
3094         gpointer iter = NULL;
3095
3096         while ((field = mono_class_get_fields (klass, &iter))) {
3097                 int foffset;
3098
3099                 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3100                         continue;
3101                 foffset = klass->valuetype ? field->offset - sizeof (MonoObject): field->offset;
3102                 if (mini_type_is_reference (cfg, mono_field_get_type (field))) {
3103                         g_assert ((foffset % SIZEOF_VOID_P) == 0);
3104                         *wb_bitmap |= 1 << ((offset + foffset) / SIZEOF_VOID_P);
3105                 } else {
3106                         MonoClass *field_class = mono_class_from_mono_type (field->type);
3107                         if (field_class->has_references)
3108                                 create_write_barrier_bitmap (cfg, field_class, wb_bitmap, offset + foffset);
3109                 }
3110         }
3111 }
3112
3113 static void
3114 emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value)
3115 {
3116         int card_table_shift_bits;
3117         gpointer card_table_mask;
3118         guint8 *card_table;
3119         MonoInst *dummy_use;
3120         int nursery_shift_bits;
3121         size_t nursery_size;
3122         gboolean has_card_table_wb = FALSE;
3123
3124         if (!cfg->gen_write_barriers)
3125                 return;
3126
3127         card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
3128
3129         mono_gc_get_nursery (&nursery_shift_bits, &nursery_size);
3130
3131 #ifdef MONO_ARCH_HAVE_CARD_TABLE_WBARRIER
3132         has_card_table_wb = TRUE;
3133 #endif
3134
3135         if (has_card_table_wb && !cfg->compile_aot && card_table && nursery_shift_bits > 0 && !COMPILE_LLVM (cfg)) {
3136                 MonoInst *wbarrier;
3137
3138                 MONO_INST_NEW (cfg, wbarrier, OP_CARD_TABLE_WBARRIER);
3139                 wbarrier->sreg1 = ptr->dreg;
3140                 wbarrier->sreg2 = value->dreg;
3141                 MONO_ADD_INS (cfg->cbb, wbarrier);
3142         } else if (card_table && !cfg->compile_aot && !mono_gc_card_table_nursery_check ()) {
3143                 int offset_reg = alloc_preg (cfg);
3144                 int card_reg  = alloc_preg (cfg);
3145                 MonoInst *ins;
3146
3147                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, offset_reg, ptr->dreg, card_table_shift_bits);
3148                 if (card_table_mask)
3149                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, offset_reg, offset_reg, card_table_mask);
3150
3151                 /*We can't use PADD_IMM since the cardtable might end up in high addresses and amd64 doesn't support
3152                  * IMM's larger than 32bits.
3153                  */
3154                 if (cfg->compile_aot) {
3155                         MONO_EMIT_NEW_AOTCONST (cfg, card_reg, NULL, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR);
3156                 } else {
3157                         MONO_INST_NEW (cfg, ins, OP_PCONST);
3158                         ins->inst_p0 = card_table;
3159                         ins->dreg = card_reg;
3160                         MONO_ADD_INS (cfg->cbb, ins);
3161                 }
3162
3163                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, offset_reg, offset_reg, card_reg);
3164                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, offset_reg, 0, 1);
3165         } else {
3166                 MonoMethod *write_barrier = mono_gc_get_write_barrier ();
3167                 mono_emit_method_call (cfg, write_barrier, &ptr, NULL);
3168         }
3169
3170         EMIT_NEW_DUMMY_USE (cfg, dummy_use, value);
3171 }
3172
3173 static gboolean
3174 mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align)
3175 {
3176         int dest_ptr_reg, tmp_reg, destreg, srcreg, offset;
3177         unsigned need_wb = 0;
3178
3179         if (align == 0)
3180                 align = 4;
3181
3182         /*types with references can't have alignment smaller than sizeof(void*) */
3183         if (align < SIZEOF_VOID_P)
3184                 return FALSE;
3185
3186         /*This value cannot be bigger than 32 due to the way we calculate the required wb bitmap.*/
3187         if (size > 32 * SIZEOF_VOID_P)
3188                 return FALSE;
3189
3190         create_write_barrier_bitmap (cfg, klass, &need_wb, 0);
3191
3192         /* We don't unroll more than 5 stores to avoid code bloat. */
3193         if (size > 5 * SIZEOF_VOID_P) {
3194                 /*This is harmless and simplify mono_gc_wbarrier_value_copy_bitmap */
3195                 size += (SIZEOF_VOID_P - 1);
3196                 size &= ~(SIZEOF_VOID_P - 1);
3197
3198                 EMIT_NEW_ICONST (cfg, iargs [2], size);
3199                 EMIT_NEW_ICONST (cfg, iargs [3], need_wb);
3200                 mono_emit_jit_icall (cfg, mono_gc_wbarrier_value_copy_bitmap, iargs);
3201                 return TRUE;
3202         }
3203
3204         destreg = iargs [0]->dreg;
3205         srcreg = iargs [1]->dreg;
3206         offset = 0;
3207
3208         dest_ptr_reg = alloc_preg (cfg);
3209         tmp_reg = alloc_preg (cfg);
3210
3211         /*tmp = dreg*/
3212         EMIT_NEW_UNALU (cfg, iargs [0], OP_MOVE, dest_ptr_reg, destreg);
3213
3214         while (size >= SIZEOF_VOID_P) {
3215                 MonoInst *load_inst;
3216                 MONO_INST_NEW (cfg, load_inst, OP_LOAD_MEMBASE);
3217                 load_inst->dreg = tmp_reg;
3218                 load_inst->inst_basereg = srcreg;
3219                 load_inst->inst_offset = offset;
3220                 MONO_ADD_INS (cfg->cbb, load_inst);
3221
3222                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg);
3223
3224                 if (need_wb & 0x1)
3225                         emit_write_barrier (cfg, iargs [0], load_inst);
3226
3227                 offset += SIZEOF_VOID_P;
3228                 size -= SIZEOF_VOID_P;
3229                 need_wb >>= 1;
3230
3231                 /*tmp += sizeof (void*)*/
3232                 if (size >= SIZEOF_VOID_P) {
3233                         NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dest_ptr_reg, dest_ptr_reg, SIZEOF_VOID_P);
3234                         MONO_ADD_INS (cfg->cbb, iargs [0]);
3235                 }
3236         }
3237
3238         /* Those cannot be references since size < sizeof (void*) */
3239         while (size >= 4) {
3240                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tmp_reg, srcreg, offset);
3241                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, tmp_reg);
3242                 offset += 4;
3243                 size -= 4;
3244         }
3245
3246         while (size >= 2) {
3247                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmp_reg, srcreg, offset);
3248                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, tmp_reg);
3249                 offset += 2;
3250                 size -= 2;
3251         }
3252
3253         while (size >= 1) {
3254                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmp_reg, srcreg, offset);
3255                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, tmp_reg);
3256                 offset += 1;
3257                 size -= 1;
3258         }
3259
3260         return TRUE;
3261 }
3262
3263 /*
3264  * Emit code to copy a valuetype of type @klass whose address is stored in
3265  * @src->dreg to memory whose address is stored at @dest->dreg.
3266  */
3267 void
3268 mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native)
3269 {
3270         MonoInst *iargs [4];
3271         int n;
3272         guint32 align = 0;
3273         MonoMethod *memcpy_method;
3274         MonoInst *size_ins = NULL;
3275         MonoInst *memcpy_ins = NULL;
3276
3277         g_assert (klass);
3278         if (cfg->generic_sharing_context)
3279                 klass = mono_class_from_mono_type (mini_get_underlying_type (cfg, &klass->byval_arg));
3280
3281         /*
3282          * This check breaks with spilled vars... need to handle it during verification anyway.
3283          * g_assert (klass && klass == src->klass && klass == dest->klass);
3284          */
3285
3286         if (mini_is_gsharedvt_klass (cfg, klass)) {
3287                 g_assert (!native);
3288                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3289                 memcpy_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_MEMCPY);
3290         }
3291
3292         if (native)
3293                 n = mono_class_native_size (klass, &align);
3294         else
3295                 n = mono_class_value_size (klass, &align);
3296
3297         /* if native is true there should be no references in the struct */
3298         if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) {
3299                 /* Avoid barriers when storing to the stack */
3300                 if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
3301                           (dest->opcode == OP_LDADDR))) {
3302                         int context_used;
3303
3304                         iargs [0] = dest;
3305                         iargs [1] = src;
3306
3307                         context_used = mini_class_check_context_used (cfg, klass);
3308
3309                         /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
3310                         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
3311                                 return;
3312                         } else if (context_used) {
3313                                 iargs [2] = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3314                         }  else {
3315                                 if (cfg->compile_aot) {
3316                                         EMIT_NEW_CLASSCONST (cfg, iargs [2], klass);
3317                                 } else {
3318                                         EMIT_NEW_PCONST (cfg, iargs [2], klass);
3319                                         mono_class_compute_gc_descriptor (klass);
3320                                 }
3321                         }
3322
3323                         if (size_ins)
3324                                 mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
3325                         else
3326                                 mono_emit_jit_icall (cfg, mono_value_copy, iargs);
3327                         return;
3328                 }
3329         }
3330
3331         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 8) {
3332                 /* FIXME: Optimize the case when src/dest is OP_LDADDR */
3333                 mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, n, align);
3334         } else {
3335                 iargs [0] = dest;
3336                 iargs [1] = src;
3337                 if (size_ins)
3338                         iargs [2] = size_ins;
3339                 else
3340                         EMIT_NEW_ICONST (cfg, iargs [2], n);
3341                 
3342                 memcpy_method = get_memcpy_method ();
3343                 if (memcpy_ins)
3344                         mono_emit_calli (cfg, mono_method_signature (memcpy_method), iargs, memcpy_ins, NULL, NULL);
3345                 else
3346                         mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
3347         }
3348 }
3349
3350 static MonoMethod*
3351 get_memset_method (void)
3352 {
3353         static MonoMethod *memset_method = NULL;
3354         if (!memset_method) {
3355                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
3356                 if (!memset_method)
3357                         g_error ("Old corlib found. Install a new one");
3358         }
3359         return memset_method;
3360 }
3361
3362 void
3363 mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass)
3364 {
3365         MonoInst *iargs [3];
3366         int n;
3367         guint32 align;
3368         MonoMethod *memset_method;
3369         MonoInst *size_ins = NULL;
3370         MonoInst *bzero_ins = NULL;
3371         static MonoMethod *bzero_method;
3372
3373         /* FIXME: Optimize this for the case when dest is an LDADDR */
3374         mono_class_init (klass);
3375         if (mini_is_gsharedvt_klass (cfg, klass)) {
3376                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3377                 bzero_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_BZERO);
3378                 if (!bzero_method)
3379                         bzero_method = mono_class_get_method_from_name (mono_defaults.string_class, "bzero_aligned_1", 2);
3380                 g_assert (bzero_method);
3381                 iargs [0] = dest;
3382                 iargs [1] = size_ins;
3383                 mono_emit_calli (cfg, mono_method_signature (bzero_method), iargs, bzero_ins, NULL, NULL);
3384                 return;
3385         }
3386
3387         n = mono_class_value_size (klass, &align);
3388
3389         if (n <= sizeof (gpointer) * 8) {
3390                 mini_emit_memset (cfg, dest->dreg, 0, n, 0, align);
3391         }
3392         else {
3393                 memset_method = get_memset_method ();
3394                 iargs [0] = dest;
3395                 EMIT_NEW_ICONST (cfg, iargs [1], 0);
3396                 EMIT_NEW_ICONST (cfg, iargs [2], n);
3397                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
3398         }
3399 }
3400
3401 static MonoInst*
3402 emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used)
3403 {
3404         MonoInst *this = NULL;
3405
3406         g_assert (cfg->generic_sharing_context);
3407
3408         if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&
3409                         !(context_used & MONO_GENERIC_CONTEXT_USED_METHOD) &&
3410                         !method->klass->valuetype)
3411                 EMIT_NEW_ARGLOAD (cfg, this, 0);
3412
3413         if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
3414                 MonoInst *mrgctx_loc, *mrgctx_var;
3415
3416                 g_assert (!this);
3417                 g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
3418
3419                 mrgctx_loc = mono_get_vtable_var (cfg);
3420                 EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
3421
3422                 return mrgctx_var;
3423         } else if (method->flags & METHOD_ATTRIBUTE_STATIC || method->klass->valuetype) {
3424                 MonoInst *vtable_loc, *vtable_var;
3425
3426                 g_assert (!this);
3427
3428                 vtable_loc = mono_get_vtable_var (cfg);
3429                 EMIT_NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
3430
3431                 if (method->is_inflated && mono_method_get_context (method)->method_inst) {
3432                         MonoInst *mrgctx_var = vtable_var;
3433                         int vtable_reg;
3434
3435                         vtable_reg = alloc_preg (cfg);
3436                         EMIT_NEW_LOAD_MEMBASE (cfg, vtable_var, OP_LOAD_MEMBASE, vtable_reg, mrgctx_var->dreg, MONO_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable));
3437                         vtable_var->type = STACK_PTR;
3438                 }
3439
3440                 return vtable_var;
3441         } else {
3442                 MonoInst *ins;
3443                 int vtable_reg;
3444         
3445                 vtable_reg = alloc_preg (cfg);
3446                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, vtable_reg, this->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3447                 return ins;
3448         }
3449 }
3450
3451 static MonoJumpInfoRgctxEntry *
3452 mono_patch_info_rgctx_entry_new (MonoMemPool *mp, MonoMethod *method, gboolean in_mrgctx, MonoJumpInfoType patch_type, gconstpointer patch_data, MonoRgctxInfoType info_type)
3453 {
3454         MonoJumpInfoRgctxEntry *res = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoRgctxEntry));
3455         res->method = method;
3456         res->in_mrgctx = in_mrgctx;
3457         res->data = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
3458         res->data->type = patch_type;
3459         res->data->data.target = patch_data;
3460         res->info_type = info_type;
3461
3462         return res;
3463 }
3464
3465 static inline MonoInst*
3466 emit_rgctx_fetch (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3467 {
3468         return mono_emit_abs_call (cfg, MONO_PATCH_INFO_RGCTX_FETCH, entry, helper_sig_rgctx_lazy_fetch_trampoline, &rgctx);
3469 }
3470
3471 static MonoInst*
3472 emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
3473                                           MonoClass *klass, MonoRgctxInfoType rgctx_type)
3474 {
3475         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);
3476         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3477
3478         return emit_rgctx_fetch (cfg, rgctx, entry);
3479 }
3480
3481 static MonoInst*
3482 emit_get_rgctx_sig (MonoCompile *cfg, int context_used,
3483                                         MonoMethodSignature *sig, MonoRgctxInfoType rgctx_type)
3484 {
3485         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);
3486         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3487
3488         return emit_rgctx_fetch (cfg, rgctx, entry);
3489 }
3490
3491 static MonoInst*
3492 emit_get_rgctx_gsharedvt_call (MonoCompile *cfg, int context_used,
3493                                                            MonoMethodSignature *sig, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3494 {
3495         MonoJumpInfoGSharedVtCall *call_info;
3496         MonoJumpInfoRgctxEntry *entry;
3497         MonoInst *rgctx;
3498
3499         call_info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoGSharedVtCall));
3500         call_info->sig = sig;
3501         call_info->method = cmethod;
3502
3503         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);
3504         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3505
3506         return emit_rgctx_fetch (cfg, rgctx, entry);
3507 }
3508
3509 /*
3510  * emit_get_rgctx_virt_method:
3511  *
3512  *   Return data for method VIRT_METHOD for a receiver of type KLASS.
3513  */
3514 static MonoInst*
3515 emit_get_rgctx_virt_method (MonoCompile *cfg, int context_used,
3516                                                         MonoClass *klass, MonoMethod *virt_method, MonoRgctxInfoType rgctx_type)
3517 {
3518         MonoJumpInfoVirtMethod *info;
3519         MonoJumpInfoRgctxEntry *entry;
3520         MonoInst *rgctx;
3521
3522         info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoVirtMethod));
3523         info->klass = klass;
3524         info->method = virt_method;
3525
3526         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);
3527         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3528
3529         return emit_rgctx_fetch (cfg, rgctx, entry);
3530 }
3531
3532 static MonoInst*
3533 emit_get_rgctx_gsharedvt_method (MonoCompile *cfg, int context_used,
3534                                                                  MonoMethod *cmethod, MonoGSharedVtMethodInfo *info)
3535 {
3536         MonoJumpInfoRgctxEntry *entry;
3537         MonoInst *rgctx;
3538
3539         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);
3540         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3541
3542         return emit_rgctx_fetch (cfg, rgctx, entry);
3543 }
3544
3545 /*
3546  * emit_get_rgctx_method:
3547  *
3548  *   Emit IR to load the property RGCTX_TYPE of CMETHOD. If context_used is 0, emit
3549  * normal constants, else emit a load from the rgctx.
3550  */
3551 static MonoInst*
3552 emit_get_rgctx_method (MonoCompile *cfg, int context_used,
3553                                            MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3554 {
3555         if (!context_used) {
3556                 MonoInst *ins;
3557
3558                 switch (rgctx_type) {
3559                 case MONO_RGCTX_INFO_METHOD:
3560                         EMIT_NEW_METHODCONST (cfg, ins, cmethod);
3561                         return ins;
3562                 case MONO_RGCTX_INFO_METHOD_RGCTX:
3563                         EMIT_NEW_METHOD_RGCTX_CONST (cfg, ins, cmethod);
3564                         return ins;
3565                 default:
3566                         g_assert_not_reached ();
3567                 }
3568         } else {
3569                 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);
3570                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3571
3572                 return emit_rgctx_fetch (cfg, rgctx, entry);
3573         }
3574 }
3575
3576 static MonoInst*
3577 emit_get_rgctx_field (MonoCompile *cfg, int context_used,
3578                                           MonoClassField *field, MonoRgctxInfoType rgctx_type)
3579 {
3580         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);
3581         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3582
3583         return emit_rgctx_fetch (cfg, rgctx, entry);
3584 }
3585
3586 static int
3587 get_gsharedvt_info_slot (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3588 {
3589         MonoGSharedVtMethodInfo *info = cfg->gsharedvt_info;
3590         MonoRuntimeGenericContextInfoTemplate *template;
3591         int i, idx;
3592
3593         g_assert (info);
3594
3595         for (i = 0; i < info->num_entries; ++i) {
3596                 MonoRuntimeGenericContextInfoTemplate *otemplate = &info->entries [i];
3597
3598                 if (otemplate->info_type == rgctx_type && otemplate->data == data && rgctx_type != MONO_RGCTX_INFO_LOCAL_OFFSET)
3599                         return i;
3600         }
3601
3602         if (info->num_entries == info->count_entries) {
3603                 MonoRuntimeGenericContextInfoTemplate *new_entries;
3604                 int new_count_entries = info->count_entries ? info->count_entries * 2 : 16;
3605
3606                 new_entries = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * new_count_entries);
3607
3608                 memcpy (new_entries, info->entries, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
3609                 info->entries = new_entries;
3610                 info->count_entries = new_count_entries;
3611         }
3612
3613         idx = info->num_entries;
3614         template = &info->entries [idx];
3615         template->info_type = rgctx_type;
3616         template->data = data;
3617
3618         info->num_entries ++;
3619
3620         return idx;
3621 }
3622
3623 /*
3624  * emit_get_gsharedvt_info:
3625  *
3626  *   This is similar to emit_get_rgctx_.., but loads the data from the gsharedvt info var instead of calling an rgctx fetch trampoline.
3627  */
3628 static MonoInst*
3629 emit_get_gsharedvt_info (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3630 {
3631         MonoInst *ins;
3632         int idx, dreg;
3633
3634         idx = get_gsharedvt_info_slot (cfg, data, rgctx_type);
3635         /* Load info->entries [idx] */
3636         dreg = alloc_preg (cfg);
3637         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, cfg->gsharedvt_info_var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
3638
3639         return ins;
3640 }
3641
3642 static MonoInst*
3643 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type)
3644 {
3645         return emit_get_gsharedvt_info (cfg, &klass->byval_arg, rgctx_type);
3646 }
3647
3648 /*
3649  * On return the caller must check @klass for load errors.
3650  */
3651 static void
3652 emit_generic_class_init (MonoCompile *cfg, MonoClass *klass)
3653 {
3654         MonoInst *vtable_arg;
3655         MonoCallInst *call;
3656         int context_used;
3657
3658         context_used = mini_class_check_context_used (cfg, klass);
3659
3660         if (context_used) {
3661                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
3662                                                                                    klass, MONO_RGCTX_INFO_VTABLE);
3663         } else {
3664                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3665
3666                 if (!vtable)
3667                         return;
3668                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
3669         }
3670
3671         if (COMPILE_LLVM (cfg))
3672                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_GENERIC_CLASS_INIT, NULL, helper_sig_generic_class_init_trampoline_llvm, &vtable_arg);
3673         else
3674                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_GENERIC_CLASS_INIT, NULL, helper_sig_generic_class_init_trampoline, &vtable_arg);
3675 #ifdef MONO_ARCH_VTABLE_REG
3676         mono_call_inst_add_outarg_reg (cfg, call, vtable_arg->dreg, MONO_ARCH_VTABLE_REG, FALSE);
3677         cfg->uses_vtable_reg = TRUE;
3678 #else
3679         NOT_IMPLEMENTED;
3680 #endif
3681 }
3682
3683 static void
3684 emit_seq_point (MonoCompile *cfg, MonoMethod *method, guint8* ip, gboolean intr_loc, gboolean nonempty_stack)
3685 {
3686         MonoInst *ins;
3687
3688         if (cfg->gen_seq_points && cfg->method == method) {
3689                 NEW_SEQ_POINT (cfg, ins, ip - cfg->header->code, intr_loc);
3690                 if (nonempty_stack)
3691                         ins->flags |= MONO_INST_NONEMPTY_STACK;
3692                 MONO_ADD_INS (cfg->cbb, ins);
3693         }
3694 }
3695
3696 static void
3697 save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean null_check, MonoBasicBlock **out_bblock)
3698 {
3699         if (mini_get_debug_options ()->better_cast_details) {
3700                 int vtable_reg = alloc_preg (cfg);
3701                 int klass_reg = alloc_preg (cfg);
3702                 MonoBasicBlock *is_null_bb = NULL;
3703                 MonoInst *tls_get;
3704                 int to_klass_reg, context_used;
3705
3706                 if (null_check) {
3707                         NEW_BBLOCK (cfg, is_null_bb);
3708
3709                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3710                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3711                 }
3712
3713                 tls_get = mono_get_jit_tls_intrinsic (cfg);
3714                 if (!tls_get) {
3715                         fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
3716                         exit (1);
3717                 }
3718
3719                 MONO_ADD_INS (cfg->cbb, tls_get);
3720                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3721                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3722
3723                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
3724
3725                 context_used = mini_class_check_context_used (cfg, klass);
3726                 if (context_used) {
3727                         MonoInst *class_ins;
3728
3729                         class_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3730                         to_klass_reg = class_ins->dreg;
3731                 } else {
3732                         to_klass_reg = alloc_preg (cfg);
3733                         MONO_EMIT_NEW_CLASSCONST (cfg, to_klass_reg, klass);
3734                 }
3735                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
3736
3737                 if (null_check) {
3738                         MONO_START_BB (cfg, is_null_bb);
3739                         if (out_bblock)
3740                                 *out_bblock = cfg->cbb;
3741                 }
3742         }
3743 }
3744
3745 static void
3746 reset_cast_details (MonoCompile *cfg)
3747 {
3748         /* Reset the variables holding the cast details */
3749         if (mini_get_debug_options ()->better_cast_details) {
3750                 MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
3751
3752                 MONO_ADD_INS (cfg->cbb, tls_get);
3753                 /* It is enough to reset the from field */
3754                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
3755         }
3756 }
3757
3758 /*
3759  * On return the caller must check @array_class for load errors
3760  */
3761 static void
3762 mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_class)
3763 {
3764         int vtable_reg = alloc_preg (cfg);
3765         int context_used;
3766
3767         context_used = mini_class_check_context_used (cfg, array_class);
3768
3769         save_cast_details (cfg, array_class, obj->dreg, FALSE, NULL);
3770
3771         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3772
3773         if (cfg->opt & MONO_OPT_SHARED) {
3774                 int class_reg = alloc_preg (cfg);
3775                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, class_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3776                 if (cfg->compile_aot) {
3777                         int klass_reg = alloc_preg (cfg);
3778                         MONO_EMIT_NEW_CLASSCONST (cfg, klass_reg, array_class);
3779                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, class_reg, klass_reg);
3780                 } else {
3781                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, class_reg, array_class);
3782                 }
3783         } else if (context_used) {
3784                 MonoInst *vtable_ins;
3785
3786                 vtable_ins = emit_get_rgctx_klass (cfg, context_used, array_class, MONO_RGCTX_INFO_VTABLE);
3787                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vtable_ins->dreg);
3788         } else {
3789                 if (cfg->compile_aot) {
3790                         int vt_reg;
3791                         MonoVTable *vtable;
3792
3793                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3794                                 return;
3795                         vt_reg = alloc_preg (cfg);
3796                         MONO_EMIT_NEW_VTABLECONST (cfg, vt_reg, vtable);
3797                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vt_reg);
3798                 } else {
3799                         MonoVTable *vtable;
3800                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3801                                 return;
3802                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vtable);
3803                 }
3804         }
3805         
3806         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
3807
3808         reset_cast_details (cfg);
3809 }
3810
3811 /**
3812  * Handles unbox of a Nullable<T>. If context_used is non zero, then shared 
3813  * generic code is generated.
3814  */
3815 static MonoInst*
3816 handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int context_used)
3817 {
3818         MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
3819
3820         if (context_used) {
3821                 MonoInst *rgctx, *addr;
3822
3823                 /* FIXME: What if the class is shared?  We might not
3824                    have to get the address of the method from the
3825                    RGCTX. */
3826                 addr = emit_get_rgctx_method (cfg, context_used, method,
3827                                                                           MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
3828
3829                 rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3830
3831                 return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
3832         } else {
3833                 gboolean pass_vtable, pass_mrgctx;
3834                 MonoInst *rgctx_arg = NULL;
3835
3836                 check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
3837                 g_assert (!pass_mrgctx);
3838
3839                 if (pass_vtable) {
3840                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
3841
3842                         g_assert (vtable);
3843                         EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
3844                 }
3845
3846                 return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
3847         }
3848 }
3849
3850 static MonoInst*
3851 handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_used)
3852 {
3853         MonoInst *add;
3854         int obj_reg;
3855         int vtable_reg = alloc_dreg (cfg ,STACK_PTR);
3856         int klass_reg = alloc_dreg (cfg ,STACK_PTR);
3857         int eclass_reg = alloc_dreg (cfg ,STACK_PTR);
3858         int rank_reg = alloc_dreg (cfg ,STACK_I4);
3859
3860         obj_reg = sp [0]->dreg;
3861         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3862         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
3863
3864         /* FIXME: generics */
3865         g_assert (klass->rank == 0);
3866                         
3867         // Check rank == 0
3868         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 0);
3869         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3870
3871         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3872         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, element_class));
3873
3874         if (context_used) {
3875                 MonoInst *element_class;
3876
3877                 /* This assertion is from the unboxcast insn */
3878                 g_assert (klass->rank == 0);
3879
3880                 element_class = emit_get_rgctx_klass (cfg, context_used,
3881                                 klass, MONO_RGCTX_INFO_ELEMENT_KLASS);
3882
3883                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, eclass_reg, element_class->dreg);
3884                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3885         } else {
3886                 save_cast_details (cfg, klass->element_class, obj_reg, FALSE, NULL);
3887                 mini_emit_class_check (cfg, eclass_reg, klass->element_class);
3888                 reset_cast_details (cfg);
3889         }
3890
3891         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), obj_reg, sizeof (MonoObject));
3892         MONO_ADD_INS (cfg->cbb, add);
3893         add->type = STACK_MP;
3894         add->klass = klass;
3895
3896         return add;
3897 }
3898
3899 static MonoInst*
3900 handle_unbox_gsharedvt (MonoCompile *cfg, MonoClass *klass, MonoInst *obj, MonoBasicBlock **out_cbb)
3901 {
3902         MonoInst *addr, *klass_inst, *is_ref, *args[16];
3903         MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
3904         MonoInst *ins;
3905         int dreg, addr_reg;
3906
3907         klass_inst = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_KLASS);
3908
3909         /* obj */
3910         args [0] = obj;
3911
3912         /* klass */
3913         args [1] = klass_inst;
3914
3915         /* CASTCLASS */
3916         obj = mono_emit_jit_icall (cfg, mono_object_castclass_unbox, args);
3917
3918         NEW_BBLOCK (cfg, is_ref_bb);
3919         NEW_BBLOCK (cfg, is_nullable_bb);
3920         NEW_BBLOCK (cfg, end_bb);
3921         is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
3922         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 1);
3923         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
3924
3925         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 2);
3926         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
3927
3928         /* This will contain either the address of the unboxed vtype, or an address of the temporary where the ref is stored */
3929         addr_reg = alloc_dreg (cfg, STACK_MP);
3930
3931         /* Non-ref case */
3932         /* UNBOX */
3933         NEW_BIALU_IMM (cfg, addr, OP_ADD_IMM, addr_reg, obj->dreg, sizeof (MonoObject));
3934         MONO_ADD_INS (cfg->cbb, addr);
3935
3936         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3937
3938         /* Ref case */
3939         MONO_START_BB (cfg, is_ref_bb);
3940
3941         /* Save the ref to a temporary */
3942         dreg = alloc_ireg (cfg);
3943         EMIT_NEW_VARLOADA_VREG (cfg, addr, dreg, &klass->byval_arg);
3944         addr->dreg = addr_reg;
3945         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, obj->dreg);
3946         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3947
3948         /* Nullable case */
3949         MONO_START_BB (cfg, is_nullable_bb);
3950
3951         {
3952                 MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX);
3953                 MonoInst *unbox_call;
3954                 MonoMethodSignature *unbox_sig;
3955
3956                 unbox_sig = mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
3957                 unbox_sig->ret = &klass->byval_arg;
3958                 unbox_sig->param_count = 1;
3959                 unbox_sig->params [0] = &mono_defaults.object_class->byval_arg;
3960                 unbox_call = mono_emit_calli (cfg, unbox_sig, &obj, addr, NULL, NULL);
3961
3962                 EMIT_NEW_VARLOADA_VREG (cfg, addr, unbox_call->dreg, &klass->byval_arg);
3963                 addr->dreg = addr_reg;
3964         }
3965
3966         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3967
3968         /* End */
3969         MONO_START_BB (cfg, end_bb);
3970
3971         /* LDOBJ */
3972         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr_reg, 0);
3973
3974         *out_cbb = cfg->cbb;
3975
3976         return ins;
3977 }
3978
3979 /*
3980  * Returns NULL and set the cfg exception on error.
3981  */
3982 static MonoInst*
3983 handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_used)
3984 {
3985         MonoInst *iargs [2];
3986         void *alloc_ftn;
3987
3988         if (context_used) {
3989                 MonoInst *data;
3990                 int rgctx_info;
3991                 MonoInst *iargs [2];
3992                 gboolean known_instance_size = !mini_is_gsharedvt_klass (cfg, klass);
3993
3994                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (klass, for_box, known_instance_size);
3995
3996                 if (cfg->opt & MONO_OPT_SHARED)
3997                         rgctx_info = MONO_RGCTX_INFO_KLASS;
3998                 else
3999                         rgctx_info = MONO_RGCTX_INFO_VTABLE;
4000                 data = emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
4001
4002                 if (cfg->opt & MONO_OPT_SHARED) {
4003                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4004                         iargs [1] = data;
4005                         alloc_ftn = mono_object_new;
4006                 } else {
4007                         iargs [0] = data;
4008                         alloc_ftn = mono_object_new_specific;
4009                 }
4010
4011                 if (managed_alloc && !(cfg->opt & MONO_OPT_SHARED)) {
4012                         if (known_instance_size) {
4013                                 int size = mono_class_instance_size (klass);
4014
4015                                 EMIT_NEW_ICONST (cfg, iargs [1], mono_gc_get_aligned_size_for_allocator (size));
4016                         }
4017                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4018                 }
4019
4020                 return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4021         }
4022
4023         if (cfg->opt & MONO_OPT_SHARED) {
4024                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4025                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
4026
4027                 alloc_ftn = mono_object_new;
4028         } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !klass->generic_class) {
4029                 /* This happens often in argument checking code, eg. throw new FooException... */
4030                 /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
4031                 EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
4032                 return mono_emit_jit_icall (cfg, mono_helper_newobj_mscorlib, iargs);
4033         } else {
4034                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
4035                 MonoMethod *managed_alloc = NULL;
4036                 gboolean pass_lw;
4037
4038                 if (!vtable) {
4039                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4040                         cfg->exception_ptr = klass;
4041                         return NULL;
4042                 }
4043
4044 #ifndef MONO_CROSS_COMPILE
4045                 managed_alloc = mono_gc_get_managed_allocator (klass, for_box, TRUE);
4046 #endif
4047
4048                 if (managed_alloc) {
4049                         int size = mono_class_instance_size (klass);
4050
4051                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4052                         EMIT_NEW_ICONST (cfg, iargs [1], mono_gc_get_aligned_size_for_allocator (size));
4053                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4054                 }
4055                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
4056                 if (pass_lw) {
4057                         guint32 lw = vtable->klass->instance_size;
4058                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
4059                         EMIT_NEW_ICONST (cfg, iargs [0], lw);
4060                         EMIT_NEW_VTABLECONST (cfg, iargs [1], vtable);
4061                 }
4062                 else {
4063                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4064                 }
4065         }
4066
4067         return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4068 }
4069         
4070 /*
4071  * Returns NULL and set the cfg exception on error.
4072  */     
4073 static MonoInst*
4074 handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used, MonoBasicBlock **out_cbb)
4075 {
4076         MonoInst *alloc, *ins;
4077
4078         *out_cbb = cfg->cbb;
4079
4080         if (mono_class_is_nullable (klass)) {
4081                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
4082
4083                 if (context_used) {
4084                         /* FIXME: What if the class is shared?  We might not
4085                            have to get the method address from the RGCTX. */
4086                         MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4087                                                                                                         MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4088                         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
4089
4090                         return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
4091                 } else {
4092                         gboolean pass_vtable, pass_mrgctx;
4093                         MonoInst *rgctx_arg = NULL;
4094
4095                         check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
4096                         g_assert (!pass_mrgctx);
4097
4098                         if (pass_vtable) {
4099                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4100
4101                                 g_assert (vtable);
4102                                 EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4103                         }
4104
4105                         return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4106                 }
4107         }
4108
4109         if (mini_is_gsharedvt_klass (cfg, klass)) {
4110                 MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4111                 MonoInst *res, *is_ref, *src_var, *addr;
4112                 int dreg;
4113
4114                 dreg = alloc_ireg (cfg);
4115
4116                 NEW_BBLOCK (cfg, is_ref_bb);
4117                 NEW_BBLOCK (cfg, is_nullable_bb);
4118                 NEW_BBLOCK (cfg, end_bb);
4119                 is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4120                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 1);
4121                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4122
4123                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 2);
4124                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4125
4126                 /* Non-ref case */
4127                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4128                 if (!alloc)
4129                         return NULL;
4130                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4131                 ins->opcode = OP_STOREV_MEMBASE;
4132
4133                 EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, alloc->dreg);
4134                 res->type = STACK_OBJ;
4135                 res->klass = klass;
4136                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4137                 
4138                 /* Ref case */
4139                 MONO_START_BB (cfg, is_ref_bb);
4140
4141                 /* val is a vtype, so has to load the value manually */
4142                 src_var = get_vreg_to_inst (cfg, val->dreg);
4143                 if (!src_var)
4144                         src_var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, val->dreg);
4145                 EMIT_NEW_VARLOADA (cfg, addr, src_var, src_var->inst_vtype);
4146                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, addr->dreg, 0);
4147                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4148
4149                 /* Nullable case */
4150                 MONO_START_BB (cfg, is_nullable_bb);
4151
4152                 {
4153                         MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass,
4154                                                                                                         MONO_RGCTX_INFO_NULLABLE_CLASS_BOX);
4155                         MonoInst *box_call;
4156                         MonoMethodSignature *box_sig;
4157
4158                         /*
4159                          * klass is Nullable<T>, need to call Nullable<T>.Box () using a gsharedvt signature, but we cannot
4160                          * construct that method at JIT time, so have to do things by hand.
4161                          */
4162                         box_sig = mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4163                         box_sig->ret = &mono_defaults.object_class->byval_arg;
4164                         box_sig->param_count = 1;
4165                         box_sig->params [0] = &klass->byval_arg;
4166                         box_call = mono_emit_calli (cfg, box_sig, &val, addr, NULL, NULL);
4167                         EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, box_call->dreg);
4168                         res->type = STACK_OBJ;
4169                         res->klass = klass;
4170                 }
4171
4172                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4173
4174                 MONO_START_BB (cfg, end_bb);
4175
4176                 *out_cbb = cfg->cbb;
4177
4178                 return res;
4179         } else {
4180                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4181                 if (!alloc)
4182                         return NULL;
4183
4184                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4185                 return alloc;
4186         }
4187 }
4188
4189 static gboolean
4190 mini_class_has_reference_variant_generic_argument (MonoCompile *cfg, MonoClass *klass, int context_used)
4191 {
4192         int i;
4193         MonoGenericContainer *container;
4194         MonoGenericInst *ginst;
4195
4196         if (klass->generic_class) {
4197                 container = klass->generic_class->container_class->generic_container;
4198                 ginst = klass->generic_class->context.class_inst;
4199         } else if (klass->generic_container && context_used) {
4200                 container = klass->generic_container;
4201                 ginst = container->context.class_inst;
4202         } else {
4203                 return FALSE;
4204         }
4205
4206         for (i = 0; i < container->type_argc; ++i) {
4207                 MonoType *type;
4208                 if (!(mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT)))
4209                         continue;
4210                 type = ginst->type_argv [i];
4211                 if (mini_type_is_reference (cfg, type))
4212                         return TRUE;
4213         }
4214         return FALSE;
4215 }
4216
4217 static GHashTable* direct_icall_type_hash;
4218
4219 static gboolean
4220 icall_is_direct_callable (MonoCompile *cfg, MonoMethod *cmethod)
4221 {
4222         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
4223         if (!direct_icalls_enabled (cfg))
4224                 return FALSE;
4225
4226         /*
4227          * An icall is directly callable if it doesn't directly or indirectly call mono_raise_exception ().
4228          * Whitelist a few icalls for now.
4229          */
4230         if (!direct_icall_type_hash) {
4231                 GHashTable *h = g_hash_table_new (g_str_hash, g_str_equal);
4232
4233                 g_hash_table_insert (h, (char*)"Decimal", GUINT_TO_POINTER (1));
4234                 g_hash_table_insert (h, (char*)"Number", GUINT_TO_POINTER (1));
4235                 g_hash_table_insert (h, (char*)"Buffer", GUINT_TO_POINTER (1));
4236                 mono_memory_barrier ();
4237                 direct_icall_type_hash = h;
4238         }
4239
4240         if (cmethod->klass == mono_defaults.math_class)
4241                 return TRUE;
4242         /* No locking needed */
4243         if (cmethod->klass->image == mono_defaults.corlib && g_hash_table_lookup (direct_icall_type_hash, cmethod->klass->name))
4244                 return TRUE;
4245         return FALSE;
4246 }
4247
4248 #define is_complex_isinst(klass) ((klass->flags & TYPE_ATTRIBUTE_INTERFACE) || klass->rank || mono_class_is_nullable (klass) || mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_SEALED) || klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR)
4249
4250 static MonoInst*
4251 emit_castclass_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args, MonoBasicBlock **out_bblock)
4252 {
4253         MonoMethod *mono_castclass;
4254         MonoInst *res;
4255
4256         mono_castclass = mono_marshal_get_castclass_with_cache ();
4257
4258         save_cast_details (cfg, klass, args [0]->dreg, TRUE, out_bblock);
4259         res = mono_emit_method_call (cfg, mono_castclass, args, NULL);
4260         reset_cast_details (cfg);
4261         *out_bblock = cfg->cbb;
4262
4263         return res;
4264 }
4265
4266 static int
4267 get_castclass_cache_idx (MonoCompile *cfg)
4268 {
4269         /* Each CASTCLASS_CACHE patch needs a unique index which identifies the call site */
4270         cfg->castclass_cache_index ++;
4271         return (cfg->method_index << 16) | cfg->castclass_cache_index;
4272 }
4273
4274 static MonoInst*
4275 emit_castclass_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass, MonoBasicBlock **out_bblock)
4276 {
4277         MonoInst *args [3];
4278         int idx;
4279
4280         /* obj */
4281         args [0] = obj;
4282
4283         /* klass */
4284         EMIT_NEW_CLASSCONST (cfg, args [1], klass);
4285
4286         /* inline cache*/
4287         if (cfg->compile_aot) {
4288                 idx = get_castclass_cache_idx (cfg);
4289                 EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
4290         } else {
4291                 EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
4292         }
4293
4294         /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
4295
4296         return emit_castclass_with_cache (cfg, klass, args, out_bblock);
4297 }
4298
4299 /*
4300  * Returns NULL and set the cfg exception on error.
4301  */
4302 static MonoInst*
4303 handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, guint8 *ip, MonoBasicBlock **out_bb, int *inline_costs)
4304 {
4305         MonoBasicBlock *is_null_bb;
4306         int obj_reg = src->dreg;
4307         int vtable_reg = alloc_preg (cfg);
4308         int context_used;
4309         MonoInst *klass_inst = NULL, *res;
4310         MonoBasicBlock *bblock;
4311
4312         *out_bb = cfg->cbb;
4313
4314         context_used = mini_class_check_context_used (cfg, klass);
4315
4316         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
4317                 res = emit_castclass_with_cache_nonshared (cfg, src, klass, &bblock);
4318                 (*inline_costs) += 2;
4319                 *out_bb = cfg->cbb;
4320                 return res;
4321         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
4322                 MonoMethod *mono_castclass;
4323                 MonoInst *iargs [1];
4324                 int costs;
4325
4326                 mono_castclass = mono_marshal_get_castclass (klass); 
4327                 iargs [0] = src;
4328                                 
4329                 save_cast_details (cfg, klass, src->dreg, TRUE, &bblock);
4330                 costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
4331                                                            iargs, ip, cfg->real_offset, TRUE, &bblock);
4332                 reset_cast_details (cfg);
4333                 CHECK_CFG_EXCEPTION;
4334                 g_assert (costs > 0);
4335                                 
4336                 cfg->real_offset += 5;
4337
4338                 (*inline_costs) += costs;
4339
4340                 *out_bb = cfg->cbb;
4341                 return src;
4342         }
4343
4344         if (context_used) {
4345                 MonoInst *args [3];
4346
4347                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4348                         MonoInst *cache_ins;
4349
4350                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4351
4352                         /* obj */
4353                         args [0] = src;
4354
4355                         /* klass - it's the second element of the cache entry*/
4356                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4357
4358                         /* cache */
4359                         args [2] = cache_ins;
4360
4361                         return emit_castclass_with_cache (cfg, klass, args, out_bb);
4362                 }
4363
4364                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4365         }
4366
4367         NEW_BBLOCK (cfg, is_null_bb);
4368
4369         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4370         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
4371
4372         save_cast_details (cfg, klass, obj_reg, FALSE, NULL);
4373
4374         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4375                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4376                 mini_emit_iface_cast (cfg, vtable_reg, klass, NULL, NULL);
4377         } else {
4378                 int klass_reg = alloc_preg (cfg);
4379
4380                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4381
4382                 if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4383                         /* the remoting code is broken, access the class for now */
4384                         if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4385                                 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4386                                 if (!vt) {
4387                                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4388                                         cfg->exception_ptr = klass;
4389                                         return NULL;
4390                                 }
4391                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4392                         } else {
4393                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4394                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4395                         }
4396                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4397                 } else {
4398                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4399                         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
4400                 }
4401         }
4402
4403         MONO_START_BB (cfg, is_null_bb);
4404
4405         reset_cast_details (cfg);
4406
4407         *out_bb = cfg->cbb;
4408
4409         return src;
4410
4411 exception_exit:
4412         return NULL;
4413 }
4414
4415 /*
4416  * Returns NULL and set the cfg exception on error.
4417  */
4418 static MonoInst*
4419 handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
4420 {
4421         MonoInst *ins;
4422         MonoBasicBlock *is_null_bb, *false_bb, *end_bb;
4423         int obj_reg = src->dreg;
4424         int vtable_reg = alloc_preg (cfg);
4425         int res_reg = alloc_ireg_ref (cfg);
4426         MonoInst *klass_inst = NULL;
4427
4428         if (context_used) {
4429                 MonoInst *args [3];
4430
4431                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4432                         MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
4433                         MonoInst *cache_ins;
4434
4435                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4436
4437                         /* obj */
4438                         args [0] = src;
4439
4440                         /* klass - it's the second element of the cache entry*/
4441                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4442
4443                         /* cache */
4444                         args [2] = cache_ins;
4445
4446                         return mono_emit_method_call (cfg, mono_isinst, args, NULL);
4447                 }
4448
4449                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4450         }
4451
4452         NEW_BBLOCK (cfg, is_null_bb);
4453         NEW_BBLOCK (cfg, false_bb);
4454         NEW_BBLOCK (cfg, end_bb);
4455
4456         /* Do the assignment at the beginning, so the other assignment can be if converted */
4457         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, res_reg, obj_reg);
4458         ins->type = STACK_OBJ;
4459         ins->klass = klass;
4460
4461         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4462         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_null_bb);
4463
4464         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4465
4466         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4467                 g_assert (!context_used);
4468                 /* the is_null_bb target simply copies the input register to the output */
4469                 mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb);
4470         } else {
4471                 int klass_reg = alloc_preg (cfg);
4472
4473                 if (klass->rank) {
4474                         int rank_reg = alloc_preg (cfg);
4475                         int eclass_reg = alloc_preg (cfg);
4476
4477                         g_assert (!context_used);
4478                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
4479                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
4480                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4481                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4482                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
4483                         if (klass->cast_class == mono_defaults.object_class) {
4484                                 int parent_reg = alloc_preg (cfg);
4485                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
4486                                 mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, is_null_bb);
4487                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4488                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4489                         } else if (klass->cast_class == mono_defaults.enum_class->parent) {
4490                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, is_null_bb);
4491                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);                          
4492                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4493                         } else if (klass->cast_class == mono_defaults.enum_class) {
4494                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4495                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4496                         } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
4497                                 mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4498                         } else {
4499                                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) {
4500                                         /* Check that the object is a vector too */
4501                                         int bounds_reg = alloc_preg (cfg);
4502                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
4503                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
4504                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4505                                 }
4506
4507                                 /* the is_null_bb target simply copies the input register to the output */
4508                                 mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4509                         }
4510                 } else if (mono_class_is_nullable (klass)) {
4511                         g_assert (!context_used);
4512                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4513                         /* the is_null_bb target simply copies the input register to the output */
4514                         mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
4515                 } else {
4516                         if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4517                                 g_assert (!context_used);
4518                                 /* the remoting code is broken, access the class for now */
4519                                 if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4520                                         MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4521                                         if (!vt) {
4522                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4523                                                 cfg->exception_ptr = klass;
4524                                                 return NULL;
4525                                         }
4526                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4527                                 } else {
4528                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4529                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4530                                 }
4531                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4532                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
4533                         } else {
4534                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4535                                 /* the is_null_bb target simply copies the input register to the output */
4536                                 mini_emit_isninst_cast_inst (cfg, klass_reg, klass, klass_inst, false_bb, is_null_bb);
4537                         }
4538                 }
4539         }
4540
4541         MONO_START_BB (cfg, false_bb);
4542
4543         MONO_EMIT_NEW_PCONST (cfg, res_reg, 0);
4544         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4545
4546         MONO_START_BB (cfg, is_null_bb);
4547
4548         MONO_START_BB (cfg, end_bb);
4549
4550         return ins;
4551 }
4552
4553 static MonoInst*
4554 handle_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4555 {
4556         /* This opcode takes as input an object reference and a class, and returns:
4557         0) if the object is an instance of the class,
4558         1) if the object is not instance of the class,
4559         2) if the object is a proxy whose type cannot be determined */
4560
4561         MonoInst *ins;
4562 #ifndef DISABLE_REMOTING
4563         MonoBasicBlock *true_bb, *false_bb, *false2_bb, *end_bb, *no_proxy_bb, *interface_fail_bb;
4564 #else
4565         MonoBasicBlock *true_bb, *false_bb, *end_bb;
4566 #endif
4567         int obj_reg = src->dreg;
4568         int dreg = alloc_ireg (cfg);
4569         int tmp_reg;
4570 #ifndef DISABLE_REMOTING
4571         int klass_reg = alloc_preg (cfg);
4572 #endif
4573
4574         NEW_BBLOCK (cfg, true_bb);
4575         NEW_BBLOCK (cfg, false_bb);
4576         NEW_BBLOCK (cfg, end_bb);
4577 #ifndef DISABLE_REMOTING
4578         NEW_BBLOCK (cfg, false2_bb);
4579         NEW_BBLOCK (cfg, no_proxy_bb);
4580 #endif
4581
4582         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4583         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
4584
4585         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4586 #ifndef DISABLE_REMOTING
4587                 NEW_BBLOCK (cfg, interface_fail_bb);
4588 #endif
4589
4590                 tmp_reg = alloc_preg (cfg);
4591                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4592 #ifndef DISABLE_REMOTING
4593                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, true_bb);
4594                 MONO_START_BB (cfg, interface_fail_bb);
4595                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4596                 
4597                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, false_bb);
4598
4599                 tmp_reg = alloc_preg (cfg);
4600                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4601                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4602                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false2_bb);                
4603 #else
4604                 mini_emit_iface_cast (cfg, tmp_reg, klass, false_bb, true_bb);
4605 #endif
4606         } else {
4607 #ifndef DISABLE_REMOTING
4608                 tmp_reg = alloc_preg (cfg);
4609                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4610                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4611
4612                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4613                 tmp_reg = alloc_preg (cfg);
4614                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4615                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4616
4617                 tmp_reg = alloc_preg (cfg);             
4618                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4619                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4620                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4621                 
4622                 mini_emit_isninst_cast (cfg, klass_reg, klass, false2_bb, true_bb);
4623                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false2_bb);
4624
4625                 MONO_START_BB (cfg, no_proxy_bb);
4626
4627                 mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, true_bb);
4628 #else
4629                 g_error ("transparent proxy support is disabled while trying to JIT code that uses it");
4630 #endif
4631         }
4632
4633         MONO_START_BB (cfg, false_bb);
4634
4635         MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4636         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4637
4638 #ifndef DISABLE_REMOTING
4639         MONO_START_BB (cfg, false2_bb);
4640
4641         MONO_EMIT_NEW_ICONST (cfg, dreg, 2);
4642         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4643 #endif
4644
4645         MONO_START_BB (cfg, true_bb);
4646
4647         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4648
4649         MONO_START_BB (cfg, end_bb);
4650
4651         /* FIXME: */
4652         MONO_INST_NEW (cfg, ins, OP_ICONST);
4653         ins->dreg = dreg;
4654         ins->type = STACK_I4;
4655
4656         return ins;
4657 }
4658
4659 static MonoInst*
4660 handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4661 {
4662         /* This opcode takes as input an object reference and a class, and returns:
4663         0) if the object is an instance of the class,
4664         1) if the object is a proxy whose type cannot be determined
4665         an InvalidCastException exception is thrown otherwhise*/
4666         
4667         MonoInst *ins;
4668 #ifndef DISABLE_REMOTING
4669         MonoBasicBlock *end_bb, *ok_result_bb, *no_proxy_bb, *interface_fail_bb, *fail_1_bb;
4670 #else
4671         MonoBasicBlock *ok_result_bb;
4672 #endif
4673         int obj_reg = src->dreg;
4674         int dreg = alloc_ireg (cfg);
4675         int tmp_reg = alloc_preg (cfg);
4676
4677 #ifndef DISABLE_REMOTING
4678         int klass_reg = alloc_preg (cfg);
4679         NEW_BBLOCK (cfg, end_bb);
4680 #endif
4681
4682         NEW_BBLOCK (cfg, ok_result_bb);
4683
4684         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4685         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, ok_result_bb);
4686
4687         save_cast_details (cfg, klass, obj_reg, FALSE, NULL);
4688
4689         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4690 #ifndef DISABLE_REMOTING
4691                 NEW_BBLOCK (cfg, interface_fail_bb);
4692         
4693                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4694                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, ok_result_bb);
4695                 MONO_START_BB (cfg, interface_fail_bb);
4696                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4697
4698                 mini_emit_class_check (cfg, klass_reg, mono_defaults.transparent_proxy_class);
4699
4700                 tmp_reg = alloc_preg (cfg);             
4701                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4702                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4703                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
4704                 
4705                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4706                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4707 #else
4708                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4709                 mini_emit_iface_cast (cfg, tmp_reg, klass, NULL, NULL);
4710                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, ok_result_bb);
4711 #endif
4712         } else {
4713 #ifndef DISABLE_REMOTING
4714                 NEW_BBLOCK (cfg, no_proxy_bb);
4715
4716                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4717                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4718                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4719
4720                 tmp_reg = alloc_preg (cfg);
4721                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4722                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4723
4724                 tmp_reg = alloc_preg (cfg);
4725                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4726                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4727                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4728
4729                 NEW_BBLOCK (cfg, fail_1_bb);
4730                 
4731                 mini_emit_isninst_cast (cfg, klass_reg, klass, fail_1_bb, ok_result_bb);
4732
4733                 MONO_START_BB (cfg, fail_1_bb);
4734
4735                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4736                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4737
4738                 MONO_START_BB (cfg, no_proxy_bb);
4739
4740                 mini_emit_castclass (cfg, obj_reg, klass_reg, klass, ok_result_bb);
4741 #else
4742                 g_error ("Transparent proxy support is disabled while trying to JIT code that uses it");
4743 #endif
4744         }
4745
4746         MONO_START_BB (cfg, ok_result_bb);
4747
4748         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4749
4750 #ifndef DISABLE_REMOTING
4751         MONO_START_BB (cfg, end_bb);
4752 #endif
4753
4754         /* FIXME: */
4755         MONO_INST_NEW (cfg, ins, OP_ICONST);
4756         ins->dreg = dreg;
4757         ins->type = STACK_I4;
4758
4759         return ins;
4760 }
4761
4762 static G_GNUC_UNUSED MonoInst*
4763 handle_enum_has_flag (MonoCompile *cfg, MonoClass *klass, MonoInst *enum_this, MonoInst *enum_flag)
4764 {
4765         MonoType *enum_type = mono_type_get_underlying_type (&klass->byval_arg);
4766         guint32 load_opc = mono_type_to_load_membase (cfg, enum_type);
4767         gboolean is_i4;
4768
4769         switch (enum_type->type) {
4770         case MONO_TYPE_I8:
4771         case MONO_TYPE_U8:
4772 #if SIZEOF_REGISTER == 8
4773         case MONO_TYPE_I:
4774         case MONO_TYPE_U:
4775 #endif
4776                 is_i4 = FALSE;
4777                 break;
4778         default:
4779                 is_i4 = TRUE;
4780                 break;
4781         }
4782
4783         {
4784                 MonoInst *load, *and, *cmp, *ceq;
4785                 int enum_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4786                 int and_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4787                 int dest_reg = alloc_ireg (cfg);
4788
4789                 EMIT_NEW_LOAD_MEMBASE (cfg, load, load_opc, enum_reg, enum_this->dreg, 0);
4790                 EMIT_NEW_BIALU (cfg, and, is_i4 ? OP_IAND : OP_LAND, and_reg, enum_reg, enum_flag->dreg);
4791                 EMIT_NEW_BIALU (cfg, cmp, is_i4 ? OP_ICOMPARE : OP_LCOMPARE, -1, and_reg, enum_flag->dreg);
4792                 EMIT_NEW_UNALU (cfg, ceq, is_i4 ? OP_ICEQ : OP_LCEQ, dest_reg, -1);
4793
4794                 ceq->type = STACK_I4;
4795
4796                 if (!is_i4) {
4797                         load = mono_decompose_opcode (cfg, load, NULL);
4798                         and = mono_decompose_opcode (cfg, and, NULL);
4799                         cmp = mono_decompose_opcode (cfg, cmp, NULL);
4800                         ceq = mono_decompose_opcode (cfg, ceq, NULL);
4801                 }
4802
4803                 return ceq;
4804         }
4805 }
4806
4807 /*
4808  * Returns NULL and set the cfg exception on error.
4809  */
4810 static G_GNUC_UNUSED MonoInst*
4811 handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used, gboolean virtual)
4812 {
4813         MonoInst *ptr;
4814         int dreg;
4815         gpointer trampoline;
4816         MonoInst *obj, *method_ins, *tramp_ins;
4817         MonoDomain *domain;
4818         guint8 **code_slot;
4819         
4820         // FIXME reenable optimisation for virtual case
4821         if (virtual)
4822                 return NULL;
4823
4824         if (virtual) {
4825                 MonoMethod *invoke = mono_get_delegate_invoke (klass);
4826                 g_assert (invoke);
4827
4828                 if (!mono_get_delegate_virtual_invoke_impl (mono_method_signature (invoke), context_used ? NULL : method))
4829                         return NULL;
4830         }
4831
4832         obj = handle_alloc (cfg, klass, FALSE, 0);
4833         if (!obj)
4834                 return NULL;
4835
4836         /* Inline the contents of mono_delegate_ctor */
4837
4838         /* Set target field */
4839         /* Optimize away setting of NULL target */
4840         if (!(target->opcode == OP_PCONST && target->inst_p0 == 0)) {
4841                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
4842                 if (cfg->gen_write_barriers) {
4843                         dreg = alloc_preg (cfg);
4844                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target));
4845                         emit_write_barrier (cfg, ptr, target);
4846                 }
4847         }
4848
4849         /* Set method field */
4850         method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
4851         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
4852
4853         /* 
4854          * To avoid looking up the compiled code belonging to the target method
4855          * in mono_delegate_trampoline (), we allocate a per-domain memory slot to
4856          * store it, and we fill it after the method has been compiled.
4857          */
4858         if (!method->dynamic && !(cfg->opt & MONO_OPT_SHARED)) {
4859                 MonoInst *code_slot_ins;
4860
4861                 if (context_used) {
4862                         code_slot_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD_DELEGATE_CODE);
4863                 } else {
4864                         domain = mono_domain_get ();
4865                         mono_domain_lock (domain);
4866                         if (!domain_jit_info (domain)->method_code_hash)
4867                                 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
4868                         code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
4869                         if (!code_slot) {
4870                                 code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
4871                                 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
4872                         }
4873                         mono_domain_unlock (domain);
4874
4875                         if (cfg->compile_aot)
4876                                 EMIT_NEW_AOTCONST (cfg, code_slot_ins, MONO_PATCH_INFO_METHOD_CODE_SLOT, method);
4877                         else
4878                                 EMIT_NEW_PCONST (cfg, code_slot_ins, code_slot);
4879                 }
4880                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);                
4881         }
4882
4883         if (cfg->compile_aot) {
4884                 MonoDelegateClassMethodPair *del_tramp;
4885
4886                 del_tramp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoDelegateClassMethodPair));
4887                 del_tramp->klass = klass;
4888                 del_tramp->method = context_used ? NULL : method;
4889                 del_tramp->virtual = virtual;
4890                 EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_DELEGATE_TRAMPOLINE, del_tramp);
4891         } else {
4892                 if (virtual)
4893                         trampoline = mono_create_delegate_virtual_trampoline (cfg->domain, klass, context_used ? NULL : method);
4894                 else
4895                         trampoline = mono_create_delegate_trampoline_info (cfg->domain, klass, context_used ? NULL : method);
4896                 EMIT_NEW_PCONST (cfg, tramp_ins, trampoline);
4897         }
4898
4899         /* Set invoke_impl field */
4900         if (virtual) {
4901                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), tramp_ins->dreg);
4902         } else {
4903                 dreg = alloc_preg (cfg);
4904                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, invoke_impl));
4905                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), dreg);
4906
4907                 dreg = alloc_preg (cfg);
4908                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, method_ptr));
4909                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), dreg);
4910         }
4911
4912         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
4913
4914         return obj;
4915 }
4916
4917 static MonoInst*
4918 handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
4919 {
4920         MonoJitICallInfo *info;
4921
4922         /* Need to register the icall so it gets an icall wrapper */
4923         info = mono_get_array_new_va_icall (rank);
4924
4925         cfg->flags |= MONO_CFG_HAS_VARARGS;
4926
4927         /* mono_array_new_va () needs a vararg calling convention */
4928         cfg->disable_llvm = TRUE;
4929
4930         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
4931         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
4932 }
4933
4934 /*
4935  * handle_constrained_gsharedvt_call:
4936  *
4937  *   Handle constrained calls where the receiver is a gsharedvt type.
4938  * Return the instruction representing the call. Set the cfg exception on failure.
4939  */
4940 static MonoInst*
4941 handle_constrained_gsharedvt_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp, MonoClass *constrained_class,
4942                                                                    gboolean *ref_emit_widen, MonoBasicBlock **ref_bblock)
4943 {
4944         MonoInst *ins = NULL;
4945         MonoBasicBlock *bblock = *ref_bblock;
4946         gboolean emit_widen = *ref_emit_widen;
4947
4948         /*
4949          * Constrained calls need to behave differently at runtime dependending on whenever the receiver is instantiated as ref type or as a vtype.
4950          * 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
4951          * pack the arguments into an array, and do the rest of the work in in an icall.
4952          */
4953         if (((cmethod->klass == mono_defaults.object_class) || (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) &&
4954                 (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 (cfg, fsig->ret)) &&
4955                 (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 (cfg, fsig->params [0]))))) {
4956                 MonoInst *args [16];
4957
4958                 /*
4959                  * This case handles calls to
4960                  * - object:ToString()/Equals()/GetHashCode(),
4961                  * - System.IComparable<T>:CompareTo()
4962                  * - System.IEquatable<T>:Equals ()
4963                  * plus some simple interface calls enough to support AsyncTaskMethodBuilder.
4964                  */
4965
4966                 args [0] = sp [0];
4967                 if (mono_method_check_context_used (cmethod))
4968                         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cmethod), cmethod, MONO_RGCTX_INFO_METHOD);
4969                 else
4970                         EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
4971                 args [2] = emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_class), constrained_class, MONO_RGCTX_INFO_KLASS);
4972
4973                 /* !fsig->hasthis is for the wrapper for the Object.GetType () icall */
4974                 if (fsig->hasthis && fsig->param_count) {
4975                         /* Pass the arguments using a localloc-ed array using the format expected by runtime_invoke () */
4976                         MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
4977                         ins->dreg = alloc_preg (cfg);
4978                         ins->inst_imm = fsig->param_count * sizeof (mgreg_t);
4979                         MONO_ADD_INS (cfg->cbb, ins);
4980                         args [4] = ins;
4981
4982                         if (mini_is_gsharedvt_type (cfg, fsig->params [0])) {
4983                                 int addr_reg;
4984
4985                                 args [3] = emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4986
4987                                 EMIT_NEW_VARLOADA_VREG (cfg, ins, sp [1]->dreg, fsig->params [0]);
4988                                 addr_reg = ins->dreg;
4989                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, addr_reg);
4990                         } else {
4991                                 EMIT_NEW_ICONST (cfg, args [3], 0);
4992                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, sp [1]->dreg);
4993                         }
4994                 } else {
4995                         EMIT_NEW_ICONST (cfg, args [3], 0);
4996                         EMIT_NEW_ICONST (cfg, args [4], 0);
4997                 }
4998                 ins = mono_emit_jit_icall (cfg, mono_gsharedvt_constrained_call, args);
4999                 emit_widen = FALSE;
5000
5001                 if (mini_is_gsharedvt_type (cfg, fsig->ret)) {
5002                         ins = handle_unbox_gsharedvt (cfg, mono_class_from_mono_type (fsig->ret), ins, &bblock);
5003                 } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret)) {
5004                         MonoInst *add;
5005
5006                         /* Unbox */
5007                         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), ins->dreg, sizeof (MonoObject));
5008                         MONO_ADD_INS (cfg->cbb, add);
5009                         /* Load value */
5010                         NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, add->dreg, 0);
5011                         MONO_ADD_INS (cfg->cbb, ins);
5012                         /* ins represents the call result */
5013                 }
5014         } else {
5015                 GSHAREDVT_FAILURE (CEE_CALLVIRT);
5016         }
5017
5018         *ref_emit_widen = emit_widen;
5019         *ref_bblock = bblock;
5020
5021         return ins;
5022
5023  exception_exit:
5024         return NULL;
5025 }
5026
5027 static void
5028 mono_emit_load_got_addr (MonoCompile *cfg)
5029 {
5030         MonoInst *getaddr, *dummy_use;
5031
5032         if (!cfg->got_var || cfg->got_var_allocated)
5033                 return;
5034
5035         MONO_INST_NEW (cfg, getaddr, OP_LOAD_GOTADDR);
5036         getaddr->cil_code = cfg->header->code;
5037         getaddr->dreg = cfg->got_var->dreg;
5038
5039         /* Add it to the start of the first bblock */
5040         if (cfg->bb_entry->code) {
5041                 getaddr->next = cfg->bb_entry->code;
5042                 cfg->bb_entry->code = getaddr;
5043         }
5044         else
5045                 MONO_ADD_INS (cfg->bb_entry, getaddr);
5046
5047         cfg->got_var_allocated = TRUE;
5048
5049         /* 
5050          * Add a dummy use to keep the got_var alive, since real uses might
5051          * only be generated by the back ends.
5052          * Add it to end_bblock, so the variable's lifetime covers the whole
5053          * method.
5054          * It would be better to make the usage of the got var explicit in all
5055          * cases when the backend needs it (i.e. calls, throw etc.), so this
5056          * wouldn't be needed.
5057          */
5058         NEW_DUMMY_USE (cfg, dummy_use, cfg->got_var);
5059         MONO_ADD_INS (cfg->bb_exit, dummy_use);
5060 }
5061
5062 static int inline_limit;
5063 static gboolean inline_limit_inited;
5064
5065 static gboolean
5066 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
5067 {
5068         MonoMethodHeaderSummary header;
5069         MonoVTable *vtable;
5070 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5071         MonoMethodSignature *sig = mono_method_signature (method);
5072         int i;
5073 #endif
5074
5075         if (cfg->disable_inline)
5076                 return FALSE;
5077         if (cfg->generic_sharing_context)
5078                 return FALSE;
5079
5080         if (cfg->inline_depth > 10)
5081                 return FALSE;
5082
5083 #ifdef MONO_ARCH_HAVE_LMF_OPS
5084         if (((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
5085                  (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) &&
5086             !MONO_TYPE_ISSTRUCT (signature->ret) && !mini_class_is_system_array (method->klass))
5087                 return TRUE;
5088 #endif
5089
5090
5091         if (!mono_method_get_header_summary (method, &header))
5092                 return FALSE;
5093
5094         /*runtime, icall and pinvoke are checked by summary call*/
5095         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
5096             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
5097             (mono_class_is_marshalbyref (method->klass)) ||
5098             header.has_clauses)
5099                 return FALSE;
5100
5101         /* also consider num_locals? */
5102         /* Do the size check early to avoid creating vtables */
5103         if (!inline_limit_inited) {
5104                 if (g_getenv ("MONO_INLINELIMIT"))
5105                         inline_limit = atoi (g_getenv ("MONO_INLINELIMIT"));
5106                 else
5107                         inline_limit = INLINE_LENGTH_LIMIT;
5108                 inline_limit_inited = TRUE;
5109         }
5110         if (header.code_size >= inline_limit && !(method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
5111                 return FALSE;
5112
5113         /*
5114          * if we can initialize the class of the method right away, we do,
5115          * otherwise we don't allow inlining if the class needs initialization,
5116          * since it would mean inserting a call to mono_runtime_class_init()
5117          * inside the inlined code
5118          */
5119         if (!(cfg->opt & MONO_OPT_SHARED)) {
5120                 /* The AggressiveInlining hint is a good excuse to force that cctor to run. */
5121                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING) {
5122                         vtable = mono_class_vtable (cfg->domain, method->klass);
5123                         if (!vtable)
5124                                 return FALSE;
5125                         if (!cfg->compile_aot)
5126                                 mono_runtime_class_init (vtable);
5127                 } else if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5128                         if (cfg->run_cctors && method->klass->has_cctor) {
5129                                 /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
5130                                 if (!method->klass->runtime_info)
5131                                         /* No vtable created yet */
5132                                         return FALSE;
5133                                 vtable = mono_class_vtable (cfg->domain, method->klass);
5134                                 if (!vtable)
5135                                         return FALSE;
5136                                 /* This makes so that inline cannot trigger */
5137                                 /* .cctors: too many apps depend on them */
5138                                 /* running with a specific order... */
5139                                 if (! vtable->initialized)
5140                                         return FALSE;
5141                                 mono_runtime_class_init (vtable);
5142                         }
5143                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
5144                         if (!method->klass->runtime_info)
5145                                 /* No vtable created yet */
5146                                 return FALSE;
5147                         vtable = mono_class_vtable (cfg->domain, method->klass);
5148                         if (!vtable)
5149                                 return FALSE;
5150                         if (!vtable->initialized)
5151                                 return FALSE;
5152                 }
5153         } else {
5154                 /* 
5155                  * If we're compiling for shared code
5156                  * the cctor will need to be run at aot method load time, for example,
5157                  * or at the end of the compilation of the inlining method.
5158                  */
5159                 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
5160                         return FALSE;
5161         }
5162
5163         /*
5164          * CAS - do not inline methods with declarative security
5165          * Note: this has to be before any possible return TRUE;
5166          */
5167         if (mono_security_method_has_declsec (method))
5168                 return FALSE;
5169
5170 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5171         if (mono_arch_is_soft_float ()) {
5172                 /* FIXME: */
5173                 if (sig->ret && sig->ret->type == MONO_TYPE_R4)
5174                         return FALSE;
5175                 for (i = 0; i < sig->param_count; ++i)
5176                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
5177                                 return FALSE;
5178         }
5179 #endif
5180
5181         if (g_list_find (cfg->dont_inline, method))
5182                 return FALSE;
5183
5184         return TRUE;
5185 }
5186
5187 static gboolean
5188 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoClass *klass, MonoVTable *vtable)
5189 {
5190         if (!cfg->compile_aot) {
5191                 g_assert (vtable);
5192                 if (vtable->initialized)
5193                         return FALSE;
5194         }
5195
5196         if (klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5197                 if (cfg->method == method)
5198                         return FALSE;
5199         }
5200
5201         if (!mono_class_needs_cctor_run (klass, method))
5202                 return FALSE;
5203
5204         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (klass == method->klass))
5205                 /* The initialization is already done before the method is called */
5206                 return FALSE;
5207
5208         return TRUE;
5209 }
5210
5211 static MonoInst*
5212 mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
5213 {
5214         MonoInst *ins;
5215         guint32 size;
5216         int mult_reg, add_reg, array_reg, index_reg, index2_reg;
5217         int context_used;
5218
5219         if (mini_is_gsharedvt_variable_klass (cfg, klass)) {
5220                 size = -1;
5221         } else {
5222                 mono_class_init (klass);
5223                 size = mono_class_array_element_size (klass);
5224         }
5225
5226         mult_reg = alloc_preg (cfg);
5227         array_reg = arr->dreg;
5228         index_reg = index->dreg;
5229
5230 #if SIZEOF_REGISTER == 8
5231         /* The array reg is 64 bits but the index reg is only 32 */
5232         if (COMPILE_LLVM (cfg)) {
5233                 /* Not needed */
5234                 index2_reg = index_reg;
5235         } else {
5236                 index2_reg = alloc_preg (cfg);
5237                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
5238         }
5239 #else
5240         if (index->type == STACK_I8) {
5241                 index2_reg = alloc_preg (cfg);
5242                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I4, index2_reg, index_reg);
5243         } else {
5244                 index2_reg = index_reg;
5245         }
5246 #endif
5247
5248         if (bcheck)
5249                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
5250
5251 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5252         if (size == 1 || size == 2 || size == 4 || size == 8) {
5253                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
5254
5255                 EMIT_NEW_X86_LEA (cfg, ins, array_reg, index2_reg, fast_log2 [size], MONO_STRUCT_OFFSET (MonoArray, vector));
5256                 ins->klass = mono_class_get_element_class (klass);
5257                 ins->type = STACK_MP;
5258
5259                 return ins;
5260         }
5261 #endif          
5262
5263         add_reg = alloc_ireg_mp (cfg);
5264
5265         if (size == -1) {
5266                 MonoInst *rgctx_ins;
5267
5268                 /* gsharedvt */
5269                 g_assert (cfg->generic_sharing_context);
5270                 context_used = mini_class_check_context_used (cfg, klass);
5271                 g_assert (context_used);
5272                 rgctx_ins = emit_get_gsharedvt_info (cfg, &klass->byval_arg, MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE);
5273                 MONO_EMIT_NEW_BIALU (cfg, OP_IMUL, mult_reg, index2_reg, rgctx_ins->dreg);
5274         } else {
5275                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
5276         }
5277         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
5278         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5279         ins->klass = mono_class_get_element_class (klass);
5280         ins->type = STACK_MP;
5281         MONO_ADD_INS (cfg->cbb, ins);
5282
5283         return ins;
5284 }
5285
5286 #ifndef MONO_ARCH_EMULATE_MUL_DIV
5287 static MonoInst*
5288 mini_emit_ldelema_2_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index_ins1, MonoInst *index_ins2)
5289 {
5290         int bounds_reg = alloc_preg (cfg);
5291         int add_reg = alloc_ireg_mp (cfg);
5292         int mult_reg = alloc_preg (cfg);
5293         int mult2_reg = alloc_preg (cfg);
5294         int low1_reg = alloc_preg (cfg);
5295         int low2_reg = alloc_preg (cfg);
5296         int high1_reg = alloc_preg (cfg);
5297         int high2_reg = alloc_preg (cfg);
5298         int realidx1_reg = alloc_preg (cfg);
5299         int realidx2_reg = alloc_preg (cfg);
5300         int sum_reg = alloc_preg (cfg);
5301         int index1, index2, tmpreg;
5302         MonoInst *ins;
5303         guint32 size;
5304
5305         mono_class_init (klass);
5306         size = mono_class_array_element_size (klass);
5307
5308         index1 = index_ins1->dreg;
5309         index2 = index_ins2->dreg;
5310
5311 #if SIZEOF_REGISTER == 8
5312         /* The array reg is 64 bits but the index reg is only 32 */
5313         if (COMPILE_LLVM (cfg)) {
5314                 /* Not needed */
5315         } else {
5316                 tmpreg = alloc_preg (cfg);
5317                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index1);
5318                 index1 = tmpreg;
5319                 tmpreg = alloc_preg (cfg);
5320                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index2);
5321                 index2 = tmpreg;
5322         }
5323 #else
5324         // FIXME: Do we need to do something here for i8 indexes, like in ldelema_1_ins ?
5325         tmpreg = -1;
5326 #endif
5327
5328         /* range checking */
5329         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, 
5330                                        arr->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5331
5332         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low1_reg, 
5333                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5334         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx1_reg, index1, low1_reg);
5335         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high1_reg, 
5336                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5337         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high1_reg, realidx1_reg);
5338         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5339
5340         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low2_reg, 
5341                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5342         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx2_reg, index2, low2_reg);
5343         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high2_reg, 
5344                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5345         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high2_reg, realidx2_reg);
5346         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5347
5348         MONO_EMIT_NEW_BIALU (cfg, OP_PMUL, mult_reg, high2_reg, realidx1_reg);
5349         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, mult_reg, realidx2_reg);
5350         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PMUL_IMM, mult2_reg, sum_reg, size);
5351         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult2_reg, arr->dreg);
5352         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5353
5354         ins->type = STACK_MP;
5355         ins->klass = klass;
5356         MONO_ADD_INS (cfg->cbb, ins);
5357
5358         return ins;
5359 }
5360 #endif
5361
5362 static MonoInst*
5363 mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
5364 {
5365         int rank;
5366         MonoInst *addr;
5367         MonoMethod *addr_method;
5368         int element_size;
5369         MonoClass *eclass = cmethod->klass->element_class;
5370
5371         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
5372
5373         if (rank == 1)
5374                 return mini_emit_ldelema_1_ins (cfg, eclass, sp [0], sp [1], TRUE);
5375
5376 #ifndef MONO_ARCH_EMULATE_MUL_DIV
5377         /* emit_ldelema_2 depends on OP_LMUL */
5378         if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS) && !mini_is_gsharedvt_variable_klass (cfg, eclass)) {
5379                 return mini_emit_ldelema_2_ins (cfg, eclass, sp [0], sp [1], sp [2]);
5380         }
5381 #endif
5382
5383         if (mini_is_gsharedvt_variable_klass (cfg, eclass))
5384                 element_size = 0;
5385         else
5386                 element_size = mono_class_array_element_size (eclass);
5387         addr_method = mono_marshal_get_array_address (rank, element_size);
5388         addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
5389
5390         return addr;
5391 }
5392
5393 static MonoBreakPolicy
5394 always_insert_breakpoint (MonoMethod *method)
5395 {
5396         return MONO_BREAK_POLICY_ALWAYS;
5397 }
5398
5399 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
5400
5401 /**
5402  * mono_set_break_policy:
5403  * policy_callback: the new callback function
5404  *
5405  * Allow embedders to decide wherther to actually obey breakpoint instructions
5406  * (both break IL instructions and Debugger.Break () method calls), for example
5407  * to not allow an app to be aborted by a perfectly valid IL opcode when executing
5408  * untrusted or semi-trusted code.
5409  *
5410  * @policy_callback will be called every time a break point instruction needs to
5411  * be inserted with the method argument being the method that calls Debugger.Break()
5412  * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
5413  * if it wants the breakpoint to not be effective in the given method.
5414  * #MONO_BREAK_POLICY_ALWAYS is the default.
5415  */
5416 void
5417 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
5418 {
5419         if (policy_callback)
5420                 break_policy_func = policy_callback;
5421         else
5422                 break_policy_func = always_insert_breakpoint;
5423 }
5424
5425 static gboolean
5426 should_insert_brekpoint (MonoMethod *method) {
5427         switch (break_policy_func (method)) {
5428         case MONO_BREAK_POLICY_ALWAYS:
5429                 return TRUE;
5430         case MONO_BREAK_POLICY_NEVER:
5431                 return FALSE;
5432         case MONO_BREAK_POLICY_ON_DBG:
5433                 g_warning ("mdb no longer supported");
5434                 return FALSE;
5435         default:
5436                 g_warning ("Incorrect value returned from break policy callback");
5437                 return FALSE;
5438         }
5439 }
5440
5441 /* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
5442 static MonoInst*
5443 emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5444 {
5445         MonoInst *addr, *store, *load;
5446         MonoClass *eklass = mono_class_from_mono_type (fsig->params [2]);
5447
5448         /* the bounds check is already done by the callers */
5449         addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5450         if (is_set) {
5451                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
5452                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
5453                 if (mini_type_is_reference (cfg, fsig->params [2]))
5454                         emit_write_barrier (cfg, addr, load);
5455         } else {
5456                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
5457                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
5458         }
5459         return store;
5460 }
5461
5462
5463 static gboolean
5464 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
5465 {
5466         return mini_type_is_reference (cfg, &klass->byval_arg);
5467 }
5468
5469 static MonoInst*
5470 emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean safety_checks)
5471 {
5472         if (safety_checks && generic_class_is_reference_type (cfg, klass) &&
5473                 !(sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL)) {
5474                 MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
5475                 MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
5476                 MonoInst *iargs [3];
5477
5478                 if (!helper->slot)
5479                         mono_class_setup_vtable (obj_array);
5480                 g_assert (helper->slot);
5481
5482                 if (sp [0]->type != STACK_OBJ)
5483                         return NULL;
5484                 if (sp [2]->type != STACK_OBJ)
5485                         return NULL;
5486
5487                 iargs [2] = sp [2];
5488                 iargs [1] = sp [1];
5489                 iargs [0] = sp [0];
5490
5491                 return mono_emit_method_call (cfg, helper, iargs, sp [0]);
5492         } else {
5493                 MonoInst *ins;
5494
5495                 if (mini_is_gsharedvt_variable_klass (cfg, klass)) {
5496                         MonoInst *addr;
5497
5498                         // FIXME-VT: OP_ICONST optimization
5499                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
5500                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5501                         ins->opcode = OP_STOREV_MEMBASE;
5502                 } else if (sp [1]->opcode == OP_ICONST) {
5503                         int array_reg = sp [0]->dreg;
5504                         int index_reg = sp [1]->dreg;
5505                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
5506
5507                         if (safety_checks)
5508                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
5509                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
5510                 } else {
5511                         MonoInst *addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], safety_checks);
5512                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5513                         if (generic_class_is_reference_type (cfg, klass))
5514                                 emit_write_barrier (cfg, addr, sp [2]);
5515                 }
5516                 return ins;
5517         }
5518 }
5519
5520 static MonoInst*
5521 emit_array_unsafe_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5522 {
5523         MonoClass *eklass;
5524         
5525         if (is_set)
5526                 eklass = mono_class_from_mono_type (fsig->params [2]);
5527         else
5528                 eklass = mono_class_from_mono_type (fsig->ret);
5529
5530         if (is_set) {
5531                 return emit_array_store (cfg, eklass, args, FALSE);
5532         } else {
5533                 MonoInst *ins, *addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5534                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &eklass->byval_arg, addr->dreg, 0);
5535                 return ins;
5536         }
5537 }
5538
5539 static gboolean
5540 is_unsafe_mov_compatible (MonoClass *param_klass, MonoClass *return_klass)
5541 {
5542         uint32_t align;
5543
5544         //Only allow for valuetypes
5545         if (!param_klass->valuetype || !return_klass->valuetype)
5546                 return FALSE;
5547
5548         //That are blitable
5549         if (param_klass->has_references || return_klass->has_references)
5550                 return FALSE;
5551
5552         /* Avoid mixing structs and primitive types/enums, they need to be handled differently in the JIT */
5553         if ((MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && !MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)) ||
5554                 (!MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)))
5555                 return FALSE;
5556
5557         if (param_klass->byval_arg.type == MONO_TYPE_R4 || param_klass->byval_arg.type == MONO_TYPE_R8 ||
5558                 return_klass->byval_arg.type == MONO_TYPE_R4 || return_klass->byval_arg.type == MONO_TYPE_R8)
5559                 return FALSE;
5560
5561         //And have the same size
5562         if (mono_class_value_size (param_klass, &align) != mono_class_value_size (return_klass, &align))
5563                 return FALSE;
5564         return TRUE;
5565 }
5566
5567 static MonoInst*
5568 emit_array_unsafe_mov (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args)
5569 {
5570         MonoClass *param_klass = mono_class_from_mono_type (fsig->params [0]);
5571         MonoClass *return_klass = mono_class_from_mono_type (fsig->ret);
5572
5573         //Valuetypes that are semantically equivalent
5574         if (is_unsafe_mov_compatible (param_klass, return_klass))
5575                 return args [0];
5576
5577         //Arrays of valuetypes that are semantically equivalent
5578         if (param_klass->rank == 1 && return_klass->rank == 1 && is_unsafe_mov_compatible (param_klass->element_class, return_klass->element_class))
5579                 return args [0];
5580
5581         return NULL;
5582 }
5583
5584 static MonoInst*
5585 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5586 {
5587 #ifdef MONO_ARCH_SIMD_INTRINSICS
5588         MonoInst *ins = NULL;
5589
5590         if (cfg->opt & MONO_OPT_SIMD) {
5591                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5592                 if (ins)
5593                         return ins;
5594         }
5595 #endif
5596
5597         return mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5598 }
5599
5600 static MonoInst*
5601 emit_memory_barrier (MonoCompile *cfg, int kind)
5602 {
5603         MonoInst *ins = NULL;
5604         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
5605         MONO_ADD_INS (cfg->cbb, ins);
5606         ins->backend.memory_barrier_kind = kind;
5607
5608         return ins;
5609 }
5610
5611 static MonoInst*
5612 llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5613 {
5614         MonoInst *ins = NULL;
5615         int opcode = 0;
5616
5617         /* The LLVM backend supports these intrinsics */
5618         if (cmethod->klass == mono_defaults.math_class) {
5619                 if (strcmp (cmethod->name, "Sin") == 0) {
5620                         opcode = OP_SIN;
5621                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5622                         opcode = OP_COS;
5623                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
5624                         opcode = OP_SQRT;
5625                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5626                         opcode = OP_ABS;
5627                 }
5628
5629                 if (opcode && fsig->param_count == 1) {
5630                         MONO_INST_NEW (cfg, ins, opcode);
5631                         ins->type = STACK_R8;
5632                         ins->dreg = mono_alloc_freg (cfg);
5633                         ins->sreg1 = args [0]->dreg;
5634                         MONO_ADD_INS (cfg->cbb, ins);
5635                 }
5636
5637                 opcode = 0;
5638                 if (cfg->opt & MONO_OPT_CMOV) {
5639                         if (strcmp (cmethod->name, "Min") == 0) {
5640                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5641                                         opcode = OP_IMIN;
5642                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5643                                         opcode = OP_IMIN_UN;
5644                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5645                                         opcode = OP_LMIN;
5646                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5647                                         opcode = OP_LMIN_UN;
5648                         } else if (strcmp (cmethod->name, "Max") == 0) {
5649                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5650                                         opcode = OP_IMAX;
5651                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5652                                         opcode = OP_IMAX_UN;
5653                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5654                                         opcode = OP_LMAX;
5655                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5656                                         opcode = OP_LMAX_UN;
5657                         }
5658                 }
5659
5660                 if (opcode && fsig->param_count == 2) {
5661                         MONO_INST_NEW (cfg, ins, opcode);
5662                         ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
5663                         ins->dreg = mono_alloc_ireg (cfg);
5664                         ins->sreg1 = args [0]->dreg;
5665                         ins->sreg2 = args [1]->dreg;
5666                         MONO_ADD_INS (cfg->cbb, ins);
5667                 }
5668         }
5669
5670         return ins;
5671 }
5672
5673 static MonoInst*
5674 mini_emit_inst_for_sharable_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5675 {
5676         if (cmethod->klass == mono_defaults.array_class) {
5677                 if (strcmp (cmethod->name, "UnsafeStore") == 0)
5678                         return emit_array_unsafe_access (cfg, fsig, args, TRUE);
5679                 else if (strcmp (cmethod->name, "UnsafeLoad") == 0)
5680                         return emit_array_unsafe_access (cfg, fsig, args, FALSE);
5681                 else if (strcmp (cmethod->name, "UnsafeMov") == 0)
5682                         return emit_array_unsafe_mov (cfg, fsig, args);
5683         }
5684
5685         return NULL;
5686 }
5687
5688 static MonoInst*
5689 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5690 {
5691         MonoInst *ins = NULL;
5692         
5693         static MonoClass *runtime_helpers_class = NULL;
5694         if (! runtime_helpers_class)
5695                 runtime_helpers_class = mono_class_from_name (mono_defaults.corlib,
5696                         "System.Runtime.CompilerServices", "RuntimeHelpers");
5697
5698         if (cmethod->klass == mono_defaults.string_class) {
5699                 if (strcmp (cmethod->name, "get_Chars") == 0 && fsig->param_count == 2) {
5700                         int dreg = alloc_ireg (cfg);
5701                         int index_reg = alloc_preg (cfg);
5702                         int add_reg = alloc_preg (cfg);
5703
5704 #if SIZEOF_REGISTER == 8
5705                         /* The array reg is 64 bits but the index reg is only 32 */
5706                         MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
5707 #else
5708                         index_reg = args [1]->dreg;
5709 #endif  
5710                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
5711
5712 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5713                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, MONO_STRUCT_OFFSET (MonoString, chars));
5714                         add_reg = ins->dreg;
5715                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5716                                                                    add_reg, 0);
5717 #else
5718                         int mult_reg = alloc_preg (cfg);
5719                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
5720                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5721                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5722                                                                    add_reg, MONO_STRUCT_OFFSET (MonoString, chars));
5723 #endif
5724                         type_from_op (cfg, ins, NULL, NULL);
5725                         return ins;
5726                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count == 1) {
5727                         int dreg = alloc_ireg (cfg);
5728                         /* Decompose later to allow more optimizations */
5729                         EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
5730                         ins->type = STACK_I4;
5731                         ins->flags |= MONO_INST_FAULT;
5732                         cfg->cbb->has_array_access = TRUE;
5733                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
5734
5735                         return ins;
5736                 } else if (strcmp (cmethod->name, "InternalSetChar") == 0 && fsig->param_count == 3) {
5737                         int mult_reg = alloc_preg (cfg);
5738                         int add_reg = alloc_preg (cfg);
5739
5740                         /* The corlib functions check for oob already. */
5741                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, args [1]->dreg, 1);
5742                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5743                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, add_reg, MONO_STRUCT_OFFSET (MonoString, chars), args [2]->dreg);
5744                         return cfg->cbb->last_ins;
5745                 } else 
5746                         return NULL;
5747         } else if (cmethod->klass == mono_defaults.object_class) {
5748
5749                 if (strcmp (cmethod->name, "GetType") == 0 && fsig->param_count == 1) {
5750                         int dreg = alloc_ireg_ref (cfg);
5751                         int vt_reg = alloc_preg (cfg);
5752                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5753                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, MONO_STRUCT_OFFSET (MonoVTable, type));
5754                         type_from_op (cfg, ins, NULL, NULL);
5755
5756                         return ins;
5757 #if !defined(MONO_ARCH_EMULATE_MUL_DIV)
5758                 } else if (strcmp (cmethod->name, "InternalGetHashCode") == 0 && fsig->param_count == 1 && !mono_gc_is_moving ()) {
5759                         int dreg = alloc_ireg (cfg);
5760                         int t1 = alloc_ireg (cfg);
5761         
5762                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
5763                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
5764                         ins->type = STACK_I4;
5765
5766                         return ins;
5767 #endif
5768                 } else if (strcmp (cmethod->name, ".ctor") == 0 && fsig->param_count == 0) {
5769                         MONO_INST_NEW (cfg, ins, OP_NOP);
5770                         MONO_ADD_INS (cfg->cbb, ins);
5771                         return ins;
5772                 } else
5773                         return NULL;
5774         } else if (cmethod->klass == mono_defaults.array_class) {
5775                 if (strcmp (cmethod->name, "GetGenericValueImpl") == 0 && fsig->param_count == 3 && !cfg->gsharedvt)
5776                         return emit_array_generic_access (cfg, fsig, args, FALSE);
5777                 else if (strcmp (cmethod->name, "SetGenericValueImpl") == 0 && fsig->param_count == 3 && !cfg->gsharedvt)
5778                         return emit_array_generic_access (cfg, fsig, args, TRUE);
5779
5780 #ifndef MONO_BIG_ARRAYS
5781                 /*
5782                  * This is an inline version of GetLength/GetLowerBound(0) used frequently in
5783                  * Array methods.
5784                  */
5785                 else if (((strcmp (cmethod->name, "GetLength") == 0 && fsig->param_count == 2) ||
5786                          (strcmp (cmethod->name, "GetLowerBound") == 0 && fsig->param_count == 2)) &&
5787                          args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) {
5788                         int dreg = alloc_ireg (cfg);
5789                         int bounds_reg = alloc_ireg_mp (cfg);
5790                         MonoBasicBlock *end_bb, *szarray_bb;
5791                         gboolean get_length = strcmp (cmethod->name, "GetLength") == 0;
5792
5793                         NEW_BBLOCK (cfg, end_bb);
5794                         NEW_BBLOCK (cfg, szarray_bb);
5795
5796                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOAD_MEMBASE, bounds_reg,
5797                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5798                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
5799                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, szarray_bb);
5800                         /* Non-szarray case */
5801                         if (get_length)
5802                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5803                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5804                         else
5805                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5806                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5807                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
5808                         MONO_START_BB (cfg, szarray_bb);
5809                         /* Szarray case */
5810                         if (get_length)
5811                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5812                                                                            args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
5813                         else
5814                                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
5815                         MONO_START_BB (cfg, end_bb);
5816
5817                         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg);
5818                         ins->type = STACK_I4;
5819                         
5820                         return ins;
5821                 }
5822 #endif
5823
5824                 if (cmethod->name [0] != 'g')
5825                         return NULL;
5826
5827                 if (strcmp (cmethod->name, "get_Rank") == 0 && fsig->param_count == 1) {
5828                         int dreg = alloc_ireg (cfg);
5829                         int vtable_reg = alloc_preg (cfg);
5830                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
5831                                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5832                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
5833                                                                    vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
5834                         type_from_op (cfg, ins, NULL, NULL);
5835
5836                         return ins;
5837                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count == 1) {
5838                         int dreg = alloc_ireg (cfg);
5839
5840                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
5841                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
5842                         type_from_op (cfg, ins, NULL, NULL);
5843
5844                         return ins;
5845                 } else
5846                         return NULL;
5847         } else if (cmethod->klass == runtime_helpers_class) {
5848
5849                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0 && fsig->param_count == 0) {
5850                         EMIT_NEW_ICONST (cfg, ins, MONO_STRUCT_OFFSET (MonoString, chars));
5851                         return ins;
5852                 } else
5853                         return NULL;
5854         } else if (cmethod->klass == mono_defaults.thread_class) {
5855                 if (strcmp (cmethod->name, "SpinWait_nop") == 0 && fsig->param_count == 0) {
5856                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
5857                         MONO_ADD_INS (cfg->cbb, ins);
5858                         return ins;
5859                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0) {
5860                         return emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5861                 } else if (!strcmp (cmethod->name, "VolatileRead") && fsig->param_count == 1) {
5862                         guint32 opcode = 0;
5863                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [0]);
5864
5865                         if (fsig->params [0]->type == MONO_TYPE_I1)
5866                                 opcode = OP_LOADI1_MEMBASE;
5867                         else if (fsig->params [0]->type == MONO_TYPE_U1)
5868                                 opcode = OP_LOADU1_MEMBASE;
5869                         else if (fsig->params [0]->type == MONO_TYPE_I2)
5870                                 opcode = OP_LOADI2_MEMBASE;
5871                         else if (fsig->params [0]->type == MONO_TYPE_U2)
5872                                 opcode = OP_LOADU2_MEMBASE;
5873                         else if (fsig->params [0]->type == MONO_TYPE_I4)
5874                                 opcode = OP_LOADI4_MEMBASE;
5875                         else if (fsig->params [0]->type == MONO_TYPE_U4)
5876                                 opcode = OP_LOADU4_MEMBASE;
5877                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
5878                                 opcode = OP_LOADI8_MEMBASE;
5879                         else if (fsig->params [0]->type == MONO_TYPE_R4)
5880                                 opcode = OP_LOADR4_MEMBASE;
5881                         else if (fsig->params [0]->type == MONO_TYPE_R8)
5882                                 opcode = OP_LOADR8_MEMBASE;
5883                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
5884                                 opcode = OP_LOAD_MEMBASE;
5885
5886                         if (opcode) {
5887                                 MONO_INST_NEW (cfg, ins, opcode);
5888                                 ins->inst_basereg = args [0]->dreg;
5889                                 ins->inst_offset = 0;
5890                                 MONO_ADD_INS (cfg->cbb, ins);
5891
5892                                 switch (fsig->params [0]->type) {
5893                                 case MONO_TYPE_I1:
5894                                 case MONO_TYPE_U1:
5895                                 case MONO_TYPE_I2:
5896                                 case MONO_TYPE_U2:
5897                                 case MONO_TYPE_I4:
5898                                 case MONO_TYPE_U4:
5899                                         ins->dreg = mono_alloc_ireg (cfg);
5900                                         ins->type = STACK_I4;
5901                                         break;
5902                                 case MONO_TYPE_I8:
5903                                 case MONO_TYPE_U8:
5904                                         ins->dreg = mono_alloc_lreg (cfg);
5905                                         ins->type = STACK_I8;
5906                                         break;
5907                                 case MONO_TYPE_I:
5908                                 case MONO_TYPE_U:
5909                                         ins->dreg = mono_alloc_ireg (cfg);
5910 #if SIZEOF_REGISTER == 8
5911                                         ins->type = STACK_I8;
5912 #else
5913                                         ins->type = STACK_I4;
5914 #endif
5915                                         break;
5916                                 case MONO_TYPE_R4:
5917                                 case MONO_TYPE_R8:
5918                                         ins->dreg = mono_alloc_freg (cfg);
5919                                         ins->type = STACK_R8;
5920                                         break;
5921                                 default:
5922                                         g_assert (mini_type_is_reference (cfg, fsig->params [0]));
5923                                         ins->dreg = mono_alloc_ireg_ref (cfg);
5924                                         ins->type = STACK_OBJ;
5925                                         break;
5926                                 }
5927
5928                                 if (opcode == OP_LOADI8_MEMBASE)
5929                                         ins = mono_decompose_opcode (cfg, ins, NULL);
5930
5931                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
5932
5933                                 return ins;
5934                         }
5935                 } else if (!strcmp (cmethod->name, "VolatileWrite") && fsig->param_count == 2) {
5936                         guint32 opcode = 0;
5937                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [0]);
5938
5939                         if (fsig->params [0]->type == MONO_TYPE_I1 || fsig->params [0]->type == MONO_TYPE_U1)
5940                                 opcode = OP_STOREI1_MEMBASE_REG;
5941                         else if (fsig->params [0]->type == MONO_TYPE_I2 || fsig->params [0]->type == MONO_TYPE_U2)
5942                                 opcode = OP_STOREI2_MEMBASE_REG;
5943                         else if (fsig->params [0]->type == MONO_TYPE_I4 || fsig->params [0]->type == MONO_TYPE_U4)
5944                                 opcode = OP_STOREI4_MEMBASE_REG;
5945                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
5946                                 opcode = OP_STOREI8_MEMBASE_REG;
5947                         else if (fsig->params [0]->type == MONO_TYPE_R4)
5948                                 opcode = OP_STORER4_MEMBASE_REG;
5949                         else if (fsig->params [0]->type == MONO_TYPE_R8)
5950                                 opcode = OP_STORER8_MEMBASE_REG;
5951                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
5952                                 opcode = OP_STORE_MEMBASE_REG;
5953
5954                         if (opcode) {
5955                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
5956
5957                                 MONO_INST_NEW (cfg, ins, opcode);
5958                                 ins->sreg1 = args [1]->dreg;
5959                                 ins->inst_destbasereg = args [0]->dreg;
5960                                 ins->inst_offset = 0;
5961                                 MONO_ADD_INS (cfg->cbb, ins);
5962
5963                                 if (opcode == OP_STOREI8_MEMBASE_REG)
5964                                         ins = mono_decompose_opcode (cfg, ins, NULL);
5965
5966                                 return ins;
5967                         }
5968                 }
5969         } else if (cmethod->klass == mono_defaults.monitor_class) {
5970 #if defined(MONO_ARCH_MONITOR_OBJECT_REG)
5971                 if (strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 1) {
5972                         MonoCallInst *call;
5973
5974                         if (COMPILE_LLVM (cfg)) {
5975                                 /* 
5976                                  * Pass the argument normally, the LLVM backend will handle the
5977                                  * calling convention problems.
5978                                  */
5979                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER, NULL, helper_sig_monitor_enter_exit_trampoline_llvm, args);
5980                         } else {
5981                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER,
5982                                             NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
5983                                 mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg,
5984                                                                                            MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
5985                         }
5986
5987                         return (MonoInst*)call;
5988 #if defined(MONO_ARCH_MONITOR_LOCK_TAKEN_REG)
5989                 } else if (strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 2) {
5990                         MonoCallInst *call;
5991
5992                         if (COMPILE_LLVM (cfg)) {
5993                                 /*
5994                                  * Pass the argument normally, the LLVM backend will handle the
5995                                  * calling convention problems.
5996                                  */
5997                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER_V4, NULL, helper_sig_monitor_enter_v4_trampoline_llvm, args);
5998                         } else {
5999                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER_V4,
6000                                             NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
6001                                 mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg, MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
6002                                 mono_call_inst_add_outarg_reg (cfg, call, args [1]->dreg, MONO_ARCH_MONITOR_LOCK_TAKEN_REG, FALSE);
6003                         }
6004
6005                         return (MonoInst*)call;
6006 #endif
6007                 } else if (strcmp (cmethod->name, "Exit") == 0 && fsig->param_count == 1) {
6008                         MonoCallInst *call;
6009
6010                         if (COMPILE_LLVM (cfg)) {
6011                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_EXIT, NULL, helper_sig_monitor_enter_exit_trampoline_llvm, args);
6012                         } else {
6013                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_EXIT,
6014                                             NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
6015                                 mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg,
6016                                                                                            MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
6017                         }
6018
6019                         return (MonoInst*)call;
6020                 }
6021 #endif
6022         } else if (cmethod->klass->image == mono_defaults.corlib &&
6023                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6024                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
6025                 ins = NULL;
6026
6027 #if SIZEOF_REGISTER == 8
6028                 if (strcmp (cmethod->name, "Read") == 0 && fsig->param_count == 1 && (fsig->params [0]->type == MONO_TYPE_I8)) {
6029                         if (mono_arch_opcode_supported (OP_ATOMIC_LOAD_I8)) {
6030                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_LOAD_I8);
6031                                 ins->dreg = mono_alloc_preg (cfg);
6032                                 ins->sreg1 = args [0]->dreg;
6033                                 ins->type = STACK_I8;
6034                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_SEQ;
6035                                 MONO_ADD_INS (cfg->cbb, ins);
6036                         } else {
6037                                 MonoInst *load_ins;
6038
6039                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6040
6041                                 /* 64 bit reads are already atomic */
6042                                 MONO_INST_NEW (cfg, load_ins, OP_LOADI8_MEMBASE);
6043                                 load_ins->dreg = mono_alloc_preg (cfg);
6044                                 load_ins->inst_basereg = args [0]->dreg;
6045                                 load_ins->inst_offset = 0;
6046                                 load_ins->type = STACK_I8;
6047                                 MONO_ADD_INS (cfg->cbb, load_ins);
6048
6049                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6050
6051                                 ins = load_ins;
6052                         }
6053                 }
6054 #endif
6055
6056                 if (strcmp (cmethod->name, "Increment") == 0 && fsig->param_count == 1) {
6057                         MonoInst *ins_iconst;
6058                         guint32 opcode = 0;
6059
6060                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6061                                 opcode = OP_ATOMIC_ADD_I4;
6062                                 cfg->has_atomic_add_i4 = TRUE;
6063                         }
6064 #if SIZEOF_REGISTER == 8
6065                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6066                                 opcode = OP_ATOMIC_ADD_I8;
6067 #endif
6068                         if (opcode) {
6069                                 if (!mono_arch_opcode_supported (opcode))
6070                                         return NULL;
6071                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6072                                 ins_iconst->inst_c0 = 1;
6073                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6074                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6075
6076                                 MONO_INST_NEW (cfg, ins, opcode);
6077                                 ins->dreg = mono_alloc_ireg (cfg);
6078                                 ins->inst_basereg = args [0]->dreg;
6079                                 ins->inst_offset = 0;
6080                                 ins->sreg2 = ins_iconst->dreg;
6081                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6082                                 MONO_ADD_INS (cfg->cbb, ins);
6083                         }
6084                 } else if (strcmp (cmethod->name, "Decrement") == 0 && fsig->param_count == 1) {
6085                         MonoInst *ins_iconst;
6086                         guint32 opcode = 0;
6087
6088                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6089                                 opcode = OP_ATOMIC_ADD_I4;
6090                                 cfg->has_atomic_add_i4 = TRUE;
6091                         }
6092 #if SIZEOF_REGISTER == 8
6093                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6094                                 opcode = OP_ATOMIC_ADD_I8;
6095 #endif
6096                         if (opcode) {
6097                                 if (!mono_arch_opcode_supported (opcode))
6098                                         return NULL;
6099                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6100                                 ins_iconst->inst_c0 = -1;
6101                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6102                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6103
6104                                 MONO_INST_NEW (cfg, ins, opcode);
6105                                 ins->dreg = mono_alloc_ireg (cfg);
6106                                 ins->inst_basereg = args [0]->dreg;
6107                                 ins->inst_offset = 0;
6108                                 ins->sreg2 = ins_iconst->dreg;
6109                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6110                                 MONO_ADD_INS (cfg->cbb, ins);
6111                         }
6112                 } else if (strcmp (cmethod->name, "Add") == 0 && fsig->param_count == 2) {
6113                         guint32 opcode = 0;
6114
6115                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6116                                 opcode = OP_ATOMIC_ADD_I4;
6117                                 cfg->has_atomic_add_i4 = TRUE;
6118                         }
6119 #if SIZEOF_REGISTER == 8
6120                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6121                                 opcode = OP_ATOMIC_ADD_I8;
6122 #endif
6123                         if (opcode) {
6124                                 if (!mono_arch_opcode_supported (opcode))
6125                                         return NULL;
6126                                 MONO_INST_NEW (cfg, ins, opcode);
6127                                 ins->dreg = mono_alloc_ireg (cfg);
6128                                 ins->inst_basereg = args [0]->dreg;
6129                                 ins->inst_offset = 0;
6130                                 ins->sreg2 = args [1]->dreg;
6131                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6132                                 MONO_ADD_INS (cfg->cbb, ins);
6133                         }
6134                 }
6135                 else if (strcmp (cmethod->name, "Exchange") == 0 && fsig->param_count == 2) {
6136                         MonoInst *f2i = NULL, *i2f;
6137                         guint32 opcode, f2i_opcode, i2f_opcode;
6138                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [0]);
6139                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
6140
6141                         if (fsig->params [0]->type == MONO_TYPE_I4 ||
6142                             fsig->params [0]->type == MONO_TYPE_R4) {
6143                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6144                                 f2i_opcode = OP_MOVE_F_TO_I4;
6145                                 i2f_opcode = OP_MOVE_I4_TO_F;
6146                                 cfg->has_atomic_exchange_i4 = TRUE;
6147                         }
6148 #if SIZEOF_REGISTER == 8
6149                         else if (is_ref ||
6150                                  fsig->params [0]->type == MONO_TYPE_I8 ||
6151                                  fsig->params [0]->type == MONO_TYPE_R8 ||
6152                                  fsig->params [0]->type == MONO_TYPE_I) {
6153                                 opcode = OP_ATOMIC_EXCHANGE_I8;
6154                                 f2i_opcode = OP_MOVE_F_TO_I8;
6155                                 i2f_opcode = OP_MOVE_I8_TO_F;
6156                         }
6157 #else
6158                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I) {
6159                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6160                                 cfg->has_atomic_exchange_i4 = TRUE;
6161                         }
6162 #endif
6163                         else
6164                                 return NULL;
6165
6166                         if (!mono_arch_opcode_supported (opcode))
6167                                 return NULL;
6168
6169                         if (is_float) {
6170                                 /* TODO: Decompose these opcodes instead of bailing here. */
6171                                 if (COMPILE_SOFT_FLOAT (cfg))
6172                                         return NULL;
6173
6174                                 MONO_INST_NEW (cfg, f2i, f2i_opcode);
6175                                 f2i->dreg = mono_alloc_ireg (cfg);
6176                                 f2i->sreg1 = args [1]->dreg;
6177                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6178                                         f2i->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6179                                 MONO_ADD_INS (cfg->cbb, f2i);
6180                         }
6181
6182                         MONO_INST_NEW (cfg, ins, opcode);
6183                         ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg);
6184                         ins->inst_basereg = args [0]->dreg;
6185                         ins->inst_offset = 0;
6186                         ins->sreg2 = is_float ? f2i->dreg : args [1]->dreg;
6187                         MONO_ADD_INS (cfg->cbb, ins);
6188
6189                         switch (fsig->params [0]->type) {
6190                         case MONO_TYPE_I4:
6191                                 ins->type = STACK_I4;
6192                                 break;
6193                         case MONO_TYPE_I8:
6194                                 ins->type = STACK_I8;
6195                                 break;
6196                         case MONO_TYPE_I:
6197 #if SIZEOF_REGISTER == 8
6198                                 ins->type = STACK_I8;
6199 #else
6200                                 ins->type = STACK_I4;
6201 #endif
6202                                 break;
6203                         case MONO_TYPE_R4:
6204                         case MONO_TYPE_R8:
6205                                 ins->type = STACK_R8;
6206                                 break;
6207                         default:
6208                                 g_assert (mini_type_is_reference (cfg, fsig->params [0]));
6209                                 ins->type = STACK_OBJ;
6210                                 break;
6211                         }
6212
6213                         if (is_float) {
6214                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6215                                 i2f->dreg = mono_alloc_freg (cfg);
6216                                 i2f->sreg1 = ins->dreg;
6217                                 i2f->type = STACK_R8;
6218                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6219                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6220                                 MONO_ADD_INS (cfg->cbb, i2f);
6221
6222                                 ins = i2f;
6223                         }
6224
6225                         if (cfg->gen_write_barriers && is_ref)
6226                                 emit_write_barrier (cfg, args [0], args [1]);
6227                 }
6228                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 3) {
6229                         MonoInst *f2i_new = NULL, *f2i_cmp = NULL, *i2f;
6230                         guint32 opcode, f2i_opcode, i2f_opcode;
6231                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [1]);
6232                         gboolean is_float = fsig->params [1]->type == MONO_TYPE_R4 || fsig->params [1]->type == MONO_TYPE_R8;
6233
6234                         if (fsig->params [1]->type == MONO_TYPE_I4 ||
6235                             fsig->params [1]->type == MONO_TYPE_R4) {
6236                                 opcode = OP_ATOMIC_CAS_I4;
6237                                 f2i_opcode = OP_MOVE_F_TO_I4;
6238                                 i2f_opcode = OP_MOVE_I4_TO_F;
6239                                 cfg->has_atomic_cas_i4 = TRUE;
6240                         }
6241 #if SIZEOF_REGISTER == 8
6242                         else if (is_ref ||
6243                                  fsig->params [1]->type == MONO_TYPE_I8 ||
6244                                  fsig->params [1]->type == MONO_TYPE_R8 ||
6245                                  fsig->params [1]->type == MONO_TYPE_I) {
6246                                 opcode = OP_ATOMIC_CAS_I8;
6247                                 f2i_opcode = OP_MOVE_F_TO_I8;
6248                                 i2f_opcode = OP_MOVE_I8_TO_F;
6249                         }
6250 #else
6251                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I) {
6252                                 opcode = OP_ATOMIC_CAS_I4;
6253                                 cfg->has_atomic_cas_i4 = TRUE;
6254                         }
6255 #endif
6256                         else
6257                                 return NULL;
6258
6259                         if (!mono_arch_opcode_supported (opcode))
6260                                 return NULL;
6261
6262                         if (is_float) {
6263                                 /* TODO: Decompose these opcodes instead of bailing here. */
6264                                 if (COMPILE_SOFT_FLOAT (cfg))
6265                                         return NULL;
6266
6267                                 MONO_INST_NEW (cfg, f2i_new, f2i_opcode);
6268                                 f2i_new->dreg = mono_alloc_ireg (cfg);
6269                                 f2i_new->sreg1 = args [1]->dreg;
6270                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6271                                         f2i_new->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6272                                 MONO_ADD_INS (cfg->cbb, f2i_new);
6273
6274                                 MONO_INST_NEW (cfg, f2i_cmp, f2i_opcode);
6275                                 f2i_cmp->dreg = mono_alloc_ireg (cfg);
6276                                 f2i_cmp->sreg1 = args [2]->dreg;
6277                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6278                                         f2i_cmp->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6279                                 MONO_ADD_INS (cfg->cbb, f2i_cmp);
6280                         }
6281
6282                         MONO_INST_NEW (cfg, ins, opcode);
6283                         ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
6284                         ins->sreg1 = args [0]->dreg;
6285                         ins->sreg2 = is_float ? f2i_new->dreg : args [1]->dreg;
6286                         ins->sreg3 = is_float ? f2i_cmp->dreg : args [2]->dreg;
6287                         MONO_ADD_INS (cfg->cbb, ins);
6288
6289                         switch (fsig->params [1]->type) {
6290                         case MONO_TYPE_I4:
6291                                 ins->type = STACK_I4;
6292                                 break;
6293                         case MONO_TYPE_I8:
6294                                 ins->type = STACK_I8;
6295                                 break;
6296                         case MONO_TYPE_I:
6297 #if SIZEOF_REGISTER == 8
6298                                 ins->type = STACK_I8;
6299 #else
6300                                 ins->type = STACK_I4;
6301 #endif
6302                                 break;
6303                         case MONO_TYPE_R4:
6304                         case MONO_TYPE_R8:
6305                                 ins->type = STACK_R8;
6306                                 break;
6307                         default:
6308                                 g_assert (mini_type_is_reference (cfg, fsig->params [1]));
6309                                 ins->type = STACK_OBJ;
6310                                 break;
6311                         }
6312
6313                         if (is_float) {
6314                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6315                                 i2f->dreg = mono_alloc_freg (cfg);
6316                                 i2f->sreg1 = ins->dreg;
6317                                 i2f->type = STACK_R8;
6318                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6319                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6320                                 MONO_ADD_INS (cfg->cbb, i2f);
6321
6322                                 ins = i2f;
6323                         }
6324
6325                         if (cfg->gen_write_barriers && is_ref)
6326                                 emit_write_barrier (cfg, args [0], args [1]);
6327                 }
6328                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 4 &&
6329                          fsig->params [1]->type == MONO_TYPE_I4) {
6330                         MonoInst *cmp, *ceq;
6331
6332                         if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I4))
6333                                 return NULL;
6334
6335                         /* int32 r = CAS (location, value, comparand); */
6336                         MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
6337                         ins->dreg = alloc_ireg (cfg);
6338                         ins->sreg1 = args [0]->dreg;
6339                         ins->sreg2 = args [1]->dreg;
6340                         ins->sreg3 = args [2]->dreg;
6341                         ins->type = STACK_I4;
6342                         MONO_ADD_INS (cfg->cbb, ins);
6343
6344                         /* bool result = r == comparand; */
6345                         MONO_INST_NEW (cfg, cmp, OP_ICOMPARE);
6346                         cmp->sreg1 = ins->dreg;
6347                         cmp->sreg2 = args [2]->dreg;
6348                         cmp->type = STACK_I4;
6349                         MONO_ADD_INS (cfg->cbb, cmp);
6350
6351                         MONO_INST_NEW (cfg, ceq, OP_ICEQ);
6352                         ceq->dreg = alloc_ireg (cfg);
6353                         ceq->type = STACK_I4;
6354                         MONO_ADD_INS (cfg->cbb, ceq);
6355
6356                         /* *success = result; */
6357                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, args [3]->dreg, 0, ceq->dreg);
6358
6359                         cfg->has_atomic_cas_i4 = TRUE;
6360                 }
6361                 else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0)
6362                         ins = emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6363
6364                 if (ins)
6365                         return ins;
6366         } else if (cmethod->klass->image == mono_defaults.corlib &&
6367                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6368                            (strcmp (cmethod->klass->name, "Volatile") == 0)) {
6369                 ins = NULL;
6370
6371                 if (!strcmp (cmethod->name, "Read") && fsig->param_count == 1) {
6372                         guint32 opcode = 0;
6373                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [0]);
6374                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
6375
6376                         if (fsig->params [0]->type == MONO_TYPE_I1)
6377                                 opcode = OP_ATOMIC_LOAD_I1;
6378                         else if (fsig->params [0]->type == MONO_TYPE_U1 || fsig->params [0]->type == MONO_TYPE_BOOLEAN)
6379                                 opcode = OP_ATOMIC_LOAD_U1;
6380                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6381                                 opcode = OP_ATOMIC_LOAD_I2;
6382                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6383                                 opcode = OP_ATOMIC_LOAD_U2;
6384                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6385                                 opcode = OP_ATOMIC_LOAD_I4;
6386                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6387                                 opcode = OP_ATOMIC_LOAD_U4;
6388                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6389                                 opcode = OP_ATOMIC_LOAD_R4;
6390                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6391                                 opcode = OP_ATOMIC_LOAD_R8;
6392 #if SIZEOF_REGISTER == 8
6393                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_I)
6394                                 opcode = OP_ATOMIC_LOAD_I8;
6395                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U8 || fsig->params [0]->type == MONO_TYPE_U)
6396                                 opcode = OP_ATOMIC_LOAD_U8;
6397 #else
6398                         else if (fsig->params [0]->type == MONO_TYPE_I)
6399                                 opcode = OP_ATOMIC_LOAD_I4;
6400                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U)
6401                                 opcode = OP_ATOMIC_LOAD_U4;
6402 #endif
6403
6404                         if (opcode) {
6405                                 if (!mono_arch_opcode_supported (opcode))
6406                                         return NULL;
6407
6408                                 MONO_INST_NEW (cfg, ins, opcode);
6409                                 ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : (is_float ? mono_alloc_freg (cfg) : mono_alloc_ireg (cfg));
6410                                 ins->sreg1 = args [0]->dreg;
6411                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_ACQ;
6412                                 MONO_ADD_INS (cfg->cbb, ins);
6413
6414                                 switch (fsig->params [0]->type) {
6415                                 case MONO_TYPE_BOOLEAN:
6416                                 case MONO_TYPE_I1:
6417                                 case MONO_TYPE_U1:
6418                                 case MONO_TYPE_I2:
6419                                 case MONO_TYPE_U2:
6420                                 case MONO_TYPE_I4:
6421                                 case MONO_TYPE_U4:
6422                                         ins->type = STACK_I4;
6423                                         break;
6424                                 case MONO_TYPE_I8:
6425                                 case MONO_TYPE_U8:
6426                                         ins->type = STACK_I8;
6427                                         break;
6428                                 case MONO_TYPE_I:
6429                                 case MONO_TYPE_U:
6430 #if SIZEOF_REGISTER == 8
6431                                         ins->type = STACK_I8;
6432 #else
6433                                         ins->type = STACK_I4;
6434 #endif
6435                                         break;
6436                                 case MONO_TYPE_R4:
6437                                 case MONO_TYPE_R8:
6438                                         ins->type = STACK_R8;
6439                                         break;
6440                                 default:
6441                                         g_assert (mini_type_is_reference (cfg, fsig->params [0]));
6442                                         ins->type = STACK_OBJ;
6443                                         break;
6444                                 }
6445                         }
6446                 }
6447
6448                 if (!strcmp (cmethod->name, "Write") && fsig->param_count == 2) {
6449                         guint32 opcode = 0;
6450                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [0]);
6451
6452                         if (fsig->params [0]->type == MONO_TYPE_I1)
6453                                 opcode = OP_ATOMIC_STORE_I1;
6454                         else if (fsig->params [0]->type == MONO_TYPE_U1 || fsig->params [0]->type == MONO_TYPE_BOOLEAN)
6455                                 opcode = OP_ATOMIC_STORE_U1;
6456                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6457                                 opcode = OP_ATOMIC_STORE_I2;
6458                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6459                                 opcode = OP_ATOMIC_STORE_U2;
6460                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6461                                 opcode = OP_ATOMIC_STORE_I4;
6462                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6463                                 opcode = OP_ATOMIC_STORE_U4;
6464                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6465                                 opcode = OP_ATOMIC_STORE_R4;
6466                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6467                                 opcode = OP_ATOMIC_STORE_R8;
6468 #if SIZEOF_REGISTER == 8
6469                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_I)
6470                                 opcode = OP_ATOMIC_STORE_I8;
6471                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U8 || fsig->params [0]->type == MONO_TYPE_U)
6472                                 opcode = OP_ATOMIC_STORE_U8;
6473 #else
6474                         else if (fsig->params [0]->type == MONO_TYPE_I)
6475                                 opcode = OP_ATOMIC_STORE_I4;
6476                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U)
6477                                 opcode = OP_ATOMIC_STORE_U4;
6478 #endif
6479
6480                         if (opcode) {
6481                                 if (!mono_arch_opcode_supported (opcode))
6482                                         return NULL;
6483
6484                                 MONO_INST_NEW (cfg, ins, opcode);
6485                                 ins->dreg = args [0]->dreg;
6486                                 ins->sreg1 = args [1]->dreg;
6487                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_REL;
6488                                 MONO_ADD_INS (cfg->cbb, ins);
6489
6490                                 if (cfg->gen_write_barriers && is_ref)
6491                                         emit_write_barrier (cfg, args [0], args [1]);
6492                         }
6493                 }
6494
6495                 if (ins)
6496                         return ins;
6497         } else if (cmethod->klass->image == mono_defaults.corlib &&
6498                            (strcmp (cmethod->klass->name_space, "System.Diagnostics") == 0) &&
6499                            (strcmp (cmethod->klass->name, "Debugger") == 0)) {
6500                 if (!strcmp (cmethod->name, "Break") && fsig->param_count == 0) {
6501                         if (should_insert_brekpoint (cfg->method)) {
6502                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
6503                         } else {
6504                                 MONO_INST_NEW (cfg, ins, OP_NOP);
6505                                 MONO_ADD_INS (cfg->cbb, ins);
6506                         }
6507                         return ins;
6508                 }
6509         } else if (cmethod->klass->image == mono_defaults.corlib &&
6510                    (strcmp (cmethod->klass->name_space, "System") == 0) &&
6511                    (strcmp (cmethod->klass->name, "Environment") == 0)) {
6512                 if (!strcmp (cmethod->name, "get_IsRunningOnWindows") && fsig->param_count == 0) {
6513 #ifdef TARGET_WIN32
6514                         EMIT_NEW_ICONST (cfg, ins, 1);
6515 #else
6516                         EMIT_NEW_ICONST (cfg, ins, 0);
6517 #endif
6518                 }
6519         } else if (cmethod->klass == mono_defaults.math_class) {
6520                 /* 
6521                  * There is general branchless code for Min/Max, but it does not work for 
6522                  * all inputs:
6523                  * http://everything2.com/?node_id=1051618
6524                  */
6525         } else if ((!strcmp (cmethod->klass->image->assembly->aname.name, "MonoMac") ||
6526                     !strcmp (cmethod->klass->image->assembly->aname.name, "monotouch")) &&
6527                    !strcmp (cmethod->klass->name_space, "XamCore.ObjCRuntime") &&
6528                    !strcmp (cmethod->klass->name, "Selector")) {
6529 #ifdef MONO_ARCH_HAVE_OBJC_GET_SELECTOR
6530                 if (!strcmp (cmethod->klass->name, "GetHandle") && fsig->param_count == 1 &&
6531                     (args [0]->opcode == OP_GOT_ENTRY || args [0]->opcode == OP_AOTCONST) &&
6532                     cfg->compile_aot) {
6533                         MonoInst *pi;
6534                         MonoJumpInfoToken *ji;
6535                         MonoString *s;
6536
6537                         cfg->disable_llvm = TRUE;
6538
6539                         if (args [0]->opcode == OP_GOT_ENTRY) {
6540                                 pi = args [0]->inst_p1;
6541                                 g_assert (pi->opcode == OP_PATCH_INFO);
6542                                 g_assert (GPOINTER_TO_INT (pi->inst_p1) == MONO_PATCH_INFO_LDSTR);
6543                                 ji = pi->inst_p0;
6544                         } else {
6545                                 g_assert (GPOINTER_TO_INT (args [0]->inst_p1) == MONO_PATCH_INFO_LDSTR);
6546                                 ji = args [0]->inst_p0;
6547                         }
6548
6549                         NULLIFY_INS (args [0]);
6550
6551                         // FIXME: Ugly
6552                         s = mono_ldstr (cfg->domain, ji->image, mono_metadata_token_index (ji->token));
6553                         MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
6554                         ins->dreg = mono_alloc_ireg (cfg);
6555                         // FIXME: Leaks
6556                         ins->inst_p0 = mono_string_to_utf8 (s);
6557                         MONO_ADD_INS (cfg->cbb, ins);
6558                         return ins;
6559                 }
6560 #endif
6561         }
6562
6563 #ifdef MONO_ARCH_SIMD_INTRINSICS
6564         if (cfg->opt & MONO_OPT_SIMD) {
6565                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
6566                 if (ins)
6567                         return ins;
6568         }
6569 #endif
6570
6571         ins = mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
6572         if (ins)
6573                 return ins;
6574
6575         if (COMPILE_LLVM (cfg)) {
6576                 ins = llvm_emit_inst_for_method (cfg, cmethod, fsig, args);
6577                 if (ins)
6578                         return ins;
6579         }
6580
6581         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
6582 }
6583
6584 /*
6585  * This entry point could be used later for arbitrary method
6586  * redirection.
6587  */
6588 inline static MonoInst*
6589 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
6590                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this)
6591 {
6592         if (method->klass == mono_defaults.string_class) {
6593                 /* managed string allocation support */
6594                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
6595                         MonoInst *iargs [2];
6596                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
6597                         MonoMethod *managed_alloc = NULL;
6598
6599                         g_assert (vtable); /*Should not fail since it System.String*/
6600 #ifndef MONO_CROSS_COMPILE
6601                         managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE, FALSE);
6602 #endif
6603                         if (!managed_alloc)
6604                                 return NULL;
6605                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
6606                         iargs [1] = args [0];
6607                         return mono_emit_method_call (cfg, managed_alloc, iargs, this);
6608                 }
6609         }
6610         return NULL;
6611 }
6612
6613 static void
6614 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
6615 {
6616         MonoInst *store, *temp;
6617         int i;
6618
6619         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
6620                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
6621
6622                 /*
6623                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
6624                  * would be different than the MonoInst's used to represent arguments, and
6625                  * the ldelema implementation can't deal with that.
6626                  * Solution: When ldelema is used on an inline argument, create a var for 
6627                  * it, emit ldelema on that var, and emit the saving code below in
6628                  * inline_method () if needed.
6629                  */
6630                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
6631                 cfg->args [i] = temp;
6632                 /* This uses cfg->args [i] which is set by the preceeding line */
6633                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
6634                 store->cil_code = sp [0]->cil_code;
6635                 sp++;
6636         }
6637 }
6638
6639 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
6640 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
6641
6642 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6643 static gboolean
6644 check_inline_called_method_name_limit (MonoMethod *called_method)
6645 {
6646         int strncmp_result;
6647         static const char *limit = NULL;
6648         
6649         if (limit == NULL) {
6650                 const char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
6651
6652                 if (limit_string != NULL)
6653                         limit = limit_string;
6654                 else
6655                         limit = "";
6656         }
6657
6658         if (limit [0] != '\0') {
6659                 char *called_method_name = mono_method_full_name (called_method, TRUE);
6660
6661                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
6662                 g_free (called_method_name);
6663         
6664                 //return (strncmp_result <= 0);
6665                 return (strncmp_result == 0);
6666         } else {
6667                 return TRUE;
6668         }
6669 }
6670 #endif
6671
6672 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6673 static gboolean
6674 check_inline_caller_method_name_limit (MonoMethod *caller_method)
6675 {
6676         int strncmp_result;
6677         static const char *limit = NULL;
6678         
6679         if (limit == NULL) {
6680                 const char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
6681                 if (limit_string != NULL) {
6682                         limit = limit_string;
6683                 } else {
6684                         limit = "";
6685                 }
6686         }
6687
6688         if (limit [0] != '\0') {
6689                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
6690
6691                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
6692                 g_free (caller_method_name);
6693         
6694                 //return (strncmp_result <= 0);
6695                 return (strncmp_result == 0);
6696         } else {
6697                 return TRUE;
6698         }
6699 }
6700 #endif
6701
6702 static void
6703 emit_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6704 {
6705         static double r8_0 = 0.0;
6706         static float r4_0 = 0.0;
6707         MonoInst *ins;
6708         int t;
6709
6710         rtype = mini_get_underlying_type (cfg, rtype);
6711         t = rtype->type;
6712
6713         if (rtype->byref) {
6714                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6715         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6716                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
6717         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6718                 MONO_EMIT_NEW_I8CONST (cfg, dreg, 0);
6719         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6720                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
6721                 ins->type = STACK_R4;
6722                 ins->inst_p0 = (void*)&r4_0;
6723                 ins->dreg = dreg;
6724                 MONO_ADD_INS (cfg->cbb, ins);
6725         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6726                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
6727                 ins->type = STACK_R8;
6728                 ins->inst_p0 = (void*)&r8_0;
6729                 ins->dreg = dreg;
6730                 MONO_ADD_INS (cfg->cbb, ins);
6731         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6732                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6733                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6734         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (cfg, rtype)) {
6735                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6736         } else {
6737                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6738         }
6739 }
6740
6741 static void
6742 emit_dummy_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6743 {
6744         int t;
6745
6746         rtype = mini_get_underlying_type (cfg, rtype);
6747         t = rtype->type;
6748
6749         if (rtype->byref) {
6750                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_PCONST);
6751         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6752                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_ICONST);
6753         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6754                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_I8CONST);
6755         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6756                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R4CONST);
6757         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6758                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R8CONST);
6759         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6760                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6761                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6762         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (cfg, rtype)) {
6763                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6764         } else {
6765                 emit_init_rvar (cfg, dreg, rtype);
6766         }
6767 }
6768
6769 /* If INIT is FALSE, emit dummy initialization statements to keep the IR valid */
6770 static void
6771 emit_init_local (MonoCompile *cfg, int local, MonoType *type, gboolean init)
6772 {
6773         MonoInst *var = cfg->locals [local];
6774         if (COMPILE_SOFT_FLOAT (cfg)) {
6775                 MonoInst *store;
6776                 int reg = alloc_dreg (cfg, var->type);
6777                 emit_init_rvar (cfg, reg, type);
6778                 EMIT_NEW_LOCSTORE (cfg, store, local, cfg->cbb->last_ins);
6779         } else {
6780                 if (init)
6781                         emit_init_rvar (cfg, var->dreg, type);
6782                 else
6783                         emit_dummy_init_rvar (cfg, var->dreg, type);
6784         }
6785 }
6786
6787 /*
6788  * inline_method:
6789  *
6790  *   Return the cost of inlining CMETHOD.
6791  */
6792 static int
6793 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
6794                            guchar *ip, guint real_offset, gboolean inline_always, MonoBasicBlock **out_cbb)
6795 {
6796         MonoInst *ins, *rvar = NULL;
6797         MonoMethodHeader *cheader;
6798         MonoBasicBlock *ebblock, *sbblock;
6799         int i, costs;
6800         MonoMethod *prev_inlined_method;
6801         MonoInst **prev_locals, **prev_args;
6802         MonoType **prev_arg_types;
6803         guint prev_real_offset;
6804         GHashTable *prev_cbb_hash;
6805         MonoBasicBlock **prev_cil_offset_to_bb;
6806         MonoBasicBlock *prev_cbb;
6807         unsigned char* prev_cil_start;
6808         guint32 prev_cil_offset_to_bb_len;
6809         MonoMethod *prev_current_method;
6810         MonoGenericContext *prev_generic_context;
6811         gboolean ret_var_set, prev_ret_var_set, prev_disable_inline, virtual = FALSE;
6812
6813         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
6814
6815 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6816         if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
6817                 return 0;
6818 #endif
6819 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6820         if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
6821                 return 0;
6822 #endif
6823
6824         if (!fsig)
6825                 fsig = mono_method_signature (cmethod);
6826
6827         if (cfg->verbose_level > 2)
6828                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6829
6830         if (!cmethod->inline_info) {
6831                 cfg->stat_inlineable_methods++;
6832                 cmethod->inline_info = 1;
6833         }
6834
6835         /* allocate local variables */
6836         cheader = mono_method_get_header (cmethod);
6837
6838         if (cheader == NULL || mono_loader_get_last_error ()) {
6839                 MonoLoaderError *error = mono_loader_get_last_error ();
6840
6841                 if (cheader)
6842                         mono_metadata_free_mh (cheader);
6843                 if (inline_always && error)
6844                         mono_cfg_set_exception (cfg, error->exception_type);
6845
6846                 mono_loader_clear_error ();
6847                 return 0;
6848         }
6849
6850         /*Must verify before creating locals as it can cause the JIT to assert.*/
6851         if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
6852                 mono_metadata_free_mh (cheader);
6853                 return 0;
6854         }
6855
6856         /* allocate space to store the return value */
6857         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
6858                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
6859         }
6860
6861         prev_locals = cfg->locals;
6862         cfg->locals = mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));     
6863         for (i = 0; i < cheader->num_locals; ++i)
6864                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
6865
6866         /* allocate start and end blocks */
6867         /* This is needed so if the inline is aborted, we can clean up */
6868         NEW_BBLOCK (cfg, sbblock);
6869         sbblock->real_offset = real_offset;
6870
6871         NEW_BBLOCK (cfg, ebblock);
6872         ebblock->block_num = cfg->num_bblocks++;
6873         ebblock->real_offset = real_offset;
6874
6875         prev_args = cfg->args;
6876         prev_arg_types = cfg->arg_types;
6877         prev_inlined_method = cfg->inlined_method;
6878         cfg->inlined_method = cmethod;
6879         cfg->ret_var_set = FALSE;
6880         cfg->inline_depth ++;
6881         prev_real_offset = cfg->real_offset;
6882         prev_cbb_hash = cfg->cbb_hash;
6883         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
6884         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
6885         prev_cil_start = cfg->cil_start;
6886         prev_cbb = cfg->cbb;
6887         prev_current_method = cfg->current_method;
6888         prev_generic_context = cfg->generic_context;
6889         prev_ret_var_set = cfg->ret_var_set;
6890         prev_disable_inline = cfg->disable_inline;
6891
6892         if (ip && *ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
6893                 virtual = TRUE;
6894
6895         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, sp, real_offset, virtual);
6896
6897         ret_var_set = cfg->ret_var_set;
6898
6899         cfg->inlined_method = prev_inlined_method;
6900         cfg->real_offset = prev_real_offset;
6901         cfg->cbb_hash = prev_cbb_hash;
6902         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
6903         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
6904         cfg->cil_start = prev_cil_start;
6905         cfg->locals = prev_locals;
6906         cfg->args = prev_args;
6907         cfg->arg_types = prev_arg_types;
6908         cfg->current_method = prev_current_method;
6909         cfg->generic_context = prev_generic_context;
6910         cfg->ret_var_set = prev_ret_var_set;
6911         cfg->disable_inline = prev_disable_inline;
6912         cfg->inline_depth --;
6913
6914         if ((costs >= 0 && costs < 60) || inline_always) {
6915                 if (cfg->verbose_level > 2)
6916                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6917                 
6918                 cfg->stat_inlined_methods++;
6919
6920                 /* always add some code to avoid block split failures */
6921                 MONO_INST_NEW (cfg, ins, OP_NOP);
6922                 MONO_ADD_INS (prev_cbb, ins);
6923
6924                 prev_cbb->next_bb = sbblock;
6925                 link_bblock (cfg, prev_cbb, sbblock);
6926
6927                 /* 
6928                  * Get rid of the begin and end bblocks if possible to aid local
6929                  * optimizations.
6930                  */
6931                 mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
6932
6933                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
6934                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
6935
6936                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
6937                         MonoBasicBlock *prev = ebblock->in_bb [0];
6938                         mono_merge_basic_blocks (cfg, prev, ebblock);
6939                         cfg->cbb = prev;
6940                         if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
6941                                 mono_merge_basic_blocks (cfg, prev_cbb, prev);
6942                                 cfg->cbb = prev_cbb;
6943                         }
6944                 } else {
6945                         /* 
6946                          * Its possible that the rvar is set in some prev bblock, but not in others.
6947                          * (#1835).
6948                          */
6949                         if (rvar) {
6950                                 MonoBasicBlock *bb;
6951
6952                                 for (i = 0; i < ebblock->in_count; ++i) {
6953                                         bb = ebblock->in_bb [i];
6954
6955                                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
6956                                                 cfg->cbb = bb;
6957
6958                                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
6959                                         }
6960                                 }
6961                         }
6962
6963                         cfg->cbb = ebblock;
6964                 }
6965
6966                 if (out_cbb)
6967                         *out_cbb = cfg->cbb;
6968
6969                 if (rvar) {
6970                         /*
6971                          * If the inlined method contains only a throw, then the ret var is not 
6972                          * set, so set it to a dummy value.
6973                          */
6974                         if (!ret_var_set)
6975                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
6976
6977                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
6978                         *sp++ = ins;
6979                 }
6980                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
6981                 return costs + 1;
6982         } else {
6983                 if (cfg->verbose_level > 2)
6984                         printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
6985                 cfg->exception_type = MONO_EXCEPTION_NONE;
6986                 mono_loader_clear_error ();
6987
6988                 /* This gets rid of the newly added bblocks */
6989                 cfg->cbb = prev_cbb;
6990         }
6991         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
6992         return 0;
6993 }
6994
6995 /*
6996  * Some of these comments may well be out-of-date.
6997  * Design decisions: we do a single pass over the IL code (and we do bblock 
6998  * splitting/merging in the few cases when it's required: a back jump to an IL
6999  * address that was not already seen as bblock starting point).
7000  * Code is validated as we go (full verification is still better left to metadata/verify.c).
7001  * Complex operations are decomposed in simpler ones right away. We need to let the 
7002  * arch-specific code peek and poke inside this process somehow (except when the 
7003  * optimizations can take advantage of the full semantic info of coarse opcodes).
7004  * All the opcodes of the form opcode.s are 'normalized' to opcode.
7005  * MonoInst->opcode initially is the IL opcode or some simplification of that 
7006  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
7007  * opcode with value bigger than OP_LAST.
7008  * At this point the IR can be handed over to an interpreter, a dumb code generator
7009  * or to the optimizing code generator that will translate it to SSA form.
7010  *
7011  * Profiling directed optimizations.
7012  * We may compile by default with few or no optimizations and instrument the code
7013  * or the user may indicate what methods to optimize the most either in a config file
7014  * or through repeated runs where the compiler applies offline the optimizations to 
7015  * each method and then decides if it was worth it.
7016  */
7017
7018 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
7019 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
7020 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
7021 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
7022 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
7023 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
7024 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
7025 #define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) TYPE_LOAD_ERROR ((klass))
7026
7027 /* offset from br.s -> br like opcodes */
7028 #define BIG_BRANCH_OFFSET 13
7029
7030 static gboolean
7031 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
7032 {
7033         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
7034
7035         return b == NULL || b == bb;
7036 }
7037
7038 static int
7039 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
7040 {
7041         unsigned char *ip = start;
7042         unsigned char *target;
7043         int i;
7044         guint cli_addr;
7045         MonoBasicBlock *bblock;
7046         const MonoOpcode *opcode;
7047
7048         while (ip < end) {
7049                 cli_addr = ip - start;
7050                 i = mono_opcode_value ((const guint8 **)&ip, end);
7051                 if (i < 0)
7052                         UNVERIFIED;
7053                 opcode = &mono_opcodes [i];
7054                 switch (opcode->argument) {
7055                 case MonoInlineNone:
7056                         ip++; 
7057                         break;
7058                 case MonoInlineString:
7059                 case MonoInlineType:
7060                 case MonoInlineField:
7061                 case MonoInlineMethod:
7062                 case MonoInlineTok:
7063                 case MonoInlineSig:
7064                 case MonoShortInlineR:
7065                 case MonoInlineI:
7066                         ip += 5;
7067                         break;
7068                 case MonoInlineVar:
7069                         ip += 3;
7070                         break;
7071                 case MonoShortInlineVar:
7072                 case MonoShortInlineI:
7073                         ip += 2;
7074                         break;
7075                 case MonoShortInlineBrTarget:
7076                         target = start + cli_addr + 2 + (signed char)ip [1];
7077                         GET_BBLOCK (cfg, bblock, target);
7078                         ip += 2;
7079                         if (ip < end)
7080                                 GET_BBLOCK (cfg, bblock, ip);
7081                         break;
7082                 case MonoInlineBrTarget:
7083                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
7084                         GET_BBLOCK (cfg, bblock, target);
7085                         ip += 5;
7086                         if (ip < end)
7087                                 GET_BBLOCK (cfg, bblock, ip);
7088                         break;
7089                 case MonoInlineSwitch: {
7090                         guint32 n = read32 (ip + 1);
7091                         guint32 j;
7092                         ip += 5;
7093                         cli_addr += 5 + 4 * n;
7094                         target = start + cli_addr;
7095                         GET_BBLOCK (cfg, bblock, target);
7096                         
7097                         for (j = 0; j < n; ++j) {
7098                                 target = start + cli_addr + (gint32)read32 (ip);
7099                                 GET_BBLOCK (cfg, bblock, target);
7100                                 ip += 4;
7101                         }
7102                         break;
7103                 }
7104                 case MonoInlineR:
7105                 case MonoInlineI8:
7106                         ip += 9;
7107                         break;
7108                 default:
7109                         g_assert_not_reached ();
7110                 }
7111
7112                 if (i == CEE_THROW) {
7113                         unsigned char *bb_start = ip - 1;
7114                         
7115                         /* Find the start of the bblock containing the throw */
7116                         bblock = NULL;
7117                         while ((bb_start >= start) && !bblock) {
7118                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
7119                                 bb_start --;
7120                         }
7121                         if (bblock)
7122                                 bblock->out_of_line = 1;
7123                 }
7124         }
7125         return 0;
7126 unverified:
7127 exception_exit:
7128         *pos = ip;
7129         return 1;
7130 }
7131
7132 static inline MonoMethod *
7133 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
7134 {
7135         MonoMethod *method;
7136
7137         if (m->wrapper_type != MONO_WRAPPER_NONE) {
7138                 method = mono_method_get_wrapper_data (m, token);
7139                 if (context) {
7140                         MonoError error;
7141                         method = mono_class_inflate_generic_method_checked (method, context, &error);
7142                         g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
7143                 }
7144         } else {
7145                 method = mono_get_method_full (m->klass->image, token, klass, context);
7146         }
7147
7148         return method;
7149 }
7150
7151 static inline MonoMethod *
7152 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
7153 {
7154         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context);
7155
7156         if (method && cfg && !cfg->generic_sharing_context && mono_class_is_open_constructed_type (&method->klass->byval_arg))
7157                 return NULL;
7158
7159         return method;
7160 }
7161
7162 static inline MonoClass*
7163 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
7164 {
7165         MonoError error;
7166         MonoClass *klass;
7167
7168         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7169                 klass = mono_method_get_wrapper_data (method, token);
7170                 if (context)
7171                         klass = mono_class_inflate_generic_class (klass, context);
7172         } else {
7173                 klass = mono_class_get_and_inflate_typespec_checked (method->klass->image, token, context, &error);
7174                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
7175         }
7176         if (klass)
7177                 mono_class_init (klass);
7178         return klass;
7179 }
7180
7181 static inline MonoMethodSignature*
7182 mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context)
7183 {
7184         MonoMethodSignature *fsig;
7185
7186         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7187                 MonoError error;
7188
7189                 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
7190                 if (context) {
7191                         fsig = mono_inflate_generic_signature (fsig, context, &error);
7192                         // FIXME:
7193                         g_assert (mono_error_ok (&error));
7194                 }
7195         } else {
7196                 fsig = mono_metadata_parse_signature (method->klass->image, token);
7197         }
7198         return fsig;
7199 }
7200
7201 /*
7202  * Returns TRUE if the JIT should abort inlining because "callee"
7203  * is influenced by security attributes.
7204  */
7205 static
7206 gboolean check_linkdemand (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
7207 {
7208         guint32 result;
7209         
7210         if ((cfg->method != caller) && mono_security_method_has_declsec (callee)) {
7211                 return TRUE;
7212         }
7213         
7214         result = mono_declsec_linkdemand (cfg->domain, caller, callee);
7215         if (result == MONO_JIT_SECURITY_OK)
7216                 return FALSE;
7217
7218         if (result == MONO_JIT_LINKDEMAND_ECMA) {
7219                 /* Generate code to throw a SecurityException before the actual call/link */
7220                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
7221                 MonoInst *args [2];
7222
7223                 NEW_ICONST (cfg, args [0], 4);
7224                 NEW_METHODCONST (cfg, args [1], caller);
7225                 mono_emit_method_call (cfg, secman->linkdemandsecurityexception, args, NULL);
7226         } else if (cfg->exception_type == MONO_EXCEPTION_NONE) {
7227                  /* don't hide previous results */
7228                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_SECURITY_LINKDEMAND);
7229                 cfg->exception_data = result;
7230                 return TRUE;
7231         }
7232         
7233         return FALSE;
7234 }
7235
7236 static MonoMethod*
7237 throw_exception (void)
7238 {
7239         static MonoMethod *method = NULL;
7240
7241         if (!method) {
7242                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
7243                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
7244         }
7245         g_assert (method);
7246         return method;
7247 }
7248
7249 static void
7250 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
7251 {
7252         MonoMethod *thrower = throw_exception ();
7253         MonoInst *args [1];
7254
7255         EMIT_NEW_PCONST (cfg, args [0], ex);
7256         mono_emit_method_call (cfg, thrower, args, NULL);
7257 }
7258
7259 /*
7260  * Return the original method is a wrapper is specified. We can only access 
7261  * the custom attributes from the original method.
7262  */
7263 static MonoMethod*
7264 get_original_method (MonoMethod *method)
7265 {
7266         if (method->wrapper_type == MONO_WRAPPER_NONE)
7267                 return method;
7268
7269         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
7270         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
7271                 return NULL;
7272
7273         /* in other cases we need to find the original method */
7274         return mono_marshal_method_from_wrapper (method);
7275 }
7276
7277 static void
7278 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field,
7279                                           MonoBasicBlock *bblock, unsigned char *ip)
7280 {
7281         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7282         MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
7283         if (ex)
7284                 emit_throw_exception (cfg, ex);
7285 }
7286
7287 static void
7288 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee,
7289                                          MonoBasicBlock *bblock, unsigned char *ip)
7290 {
7291         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7292         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
7293         if (ex)
7294                 emit_throw_exception (cfg, ex);
7295 }
7296
7297 /*
7298  * Check that the IL instructions at ip are the array initialization
7299  * sequence and return the pointer to the data and the size.
7300  */
7301 static const char*
7302 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
7303 {
7304         /*
7305          * newarr[System.Int32]
7306          * dup
7307          * ldtoken field valuetype ...
7308          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
7309          */
7310         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
7311                 MonoError error;
7312                 guint32 token = read32 (ip + 7);
7313                 guint32 field_token = read32 (ip + 2);
7314                 guint32 field_index = field_token & 0xffffff;
7315                 guint32 rva;
7316                 const char *data_ptr;
7317                 int size = 0;
7318                 MonoMethod *cmethod;
7319                 MonoClass *dummy_class;
7320                 MonoClassField *field = mono_field_from_token_checked (method->klass->image, field_token, &dummy_class, NULL, &error);
7321                 int dummy_align;
7322
7323                 if (!field) {
7324                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7325                         return NULL;
7326                 }
7327
7328                 *out_field_token = field_token;
7329
7330                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
7331                 if (!cmethod)
7332                         return NULL;
7333                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
7334                         return NULL;
7335                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
7336                 case MONO_TYPE_BOOLEAN:
7337                 case MONO_TYPE_I1:
7338                 case MONO_TYPE_U1:
7339                         size = 1; break;
7340                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
7341 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
7342                 case MONO_TYPE_CHAR:
7343                 case MONO_TYPE_I2:
7344                 case MONO_TYPE_U2:
7345                         size = 2; break;
7346                 case MONO_TYPE_I4:
7347                 case MONO_TYPE_U4:
7348                 case MONO_TYPE_R4:
7349                         size = 4; break;
7350                 case MONO_TYPE_R8:
7351                 case MONO_TYPE_I8:
7352                 case MONO_TYPE_U8:
7353                         size = 8; break;
7354 #endif
7355                 default:
7356                         return NULL;
7357                 }
7358                 size *= len;
7359                 if (size > mono_type_size (field->type, &dummy_align))
7360                     return NULL;
7361                 *out_size = size;
7362                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
7363                 if (!image_is_dynamic (method->klass->image)) {
7364                         field_index = read32 (ip + 2) & 0xffffff;
7365                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
7366                         data_ptr = mono_image_rva_map (method->klass->image, rva);
7367                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
7368                         /* for aot code we do the lookup on load */
7369                         if (aot && data_ptr)
7370                                 return GUINT_TO_POINTER (rva);
7371                 } else {
7372                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
7373                         g_assert (!aot);
7374                         data_ptr = mono_field_get_data (field);
7375                 }
7376                 return data_ptr;
7377         }
7378         return NULL;
7379 }
7380
7381 static void
7382 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
7383 {
7384         char *method_fname = mono_method_full_name (method, TRUE);
7385         char *method_code;
7386         MonoMethodHeader *header = mono_method_get_header (method);
7387
7388         if (header->code_size == 0)
7389                 method_code = g_strdup ("method body is empty.");
7390         else
7391                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
7392         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
7393         cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code);
7394         g_free (method_fname);
7395         g_free (method_code);
7396         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
7397 }
7398
7399 static void
7400 set_exception_object (MonoCompile *cfg, MonoException *exception)
7401 {
7402         mono_cfg_set_exception (cfg, MONO_EXCEPTION_OBJECT_SUPPLIED);
7403         MONO_GC_REGISTER_ROOT_SINGLE (cfg->exception_ptr);
7404         cfg->exception_ptr = exception;
7405 }
7406
7407 static void
7408 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
7409 {
7410         MonoInst *ins;
7411         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
7412         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
7413                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
7414                 /* Optimize reg-reg moves away */
7415                 /* 
7416                  * Can't optimize other opcodes, since sp[0] might point to
7417                  * the last ins of a decomposed opcode.
7418                  */
7419                 sp [0]->dreg = (cfg)->locals [n]->dreg;
7420         } else {
7421                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
7422         }
7423 }
7424
7425 /*
7426  * ldloca inhibits many optimizations so try to get rid of it in common
7427  * cases.
7428  */
7429 static inline unsigned char *
7430 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
7431 {
7432         int local, token;
7433         MonoClass *klass;
7434         MonoType *type;
7435
7436         if (size == 1) {
7437                 local = ip [1];
7438                 ip += 2;
7439         } else {
7440                 local = read16 (ip + 2);
7441                 ip += 4;
7442         }
7443         
7444         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
7445                 /* From the INITOBJ case */
7446                 token = read32 (ip + 2);
7447                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
7448                 CHECK_TYPELOAD (klass);
7449                 type = mini_get_underlying_type (cfg, &klass->byval_arg);
7450                 emit_init_local (cfg, local, type, TRUE);
7451                 return ip + 6;
7452         }
7453  exception_exit:
7454         return NULL;
7455 }
7456
7457 static gboolean
7458 is_exception_class (MonoClass *class)
7459 {
7460         while (class) {
7461                 if (class == mono_defaults.exception_class)
7462                         return TRUE;
7463                 class = class->parent;
7464         }
7465         return FALSE;
7466 }
7467
7468 /*
7469  * is_jit_optimizer_disabled:
7470  *
7471  *   Determine whenever M's assembly has a DebuggableAttribute with the
7472  * IsJITOptimizerDisabled flag set.
7473  */
7474 static gboolean
7475 is_jit_optimizer_disabled (MonoMethod *m)
7476 {
7477         MonoAssembly *ass = m->klass->image->assembly;
7478         MonoCustomAttrInfo* attrs;
7479         static MonoClass *klass;
7480         int i;
7481         gboolean val = FALSE;
7482
7483         g_assert (ass);
7484         if (ass->jit_optimizer_disabled_inited)
7485                 return ass->jit_optimizer_disabled;
7486
7487         if (!klass)
7488                 klass = mono_class_from_name (mono_defaults.corlib, "System.Diagnostics", "DebuggableAttribute");
7489         if (!klass) {
7490                 /* Linked away */
7491                 ass->jit_optimizer_disabled = FALSE;
7492                 mono_memory_barrier ();
7493                 ass->jit_optimizer_disabled_inited = TRUE;
7494                 return FALSE;
7495         }
7496
7497         attrs = mono_custom_attrs_from_assembly (ass);
7498         if (attrs) {
7499                 for (i = 0; i < attrs->num_attrs; ++i) {
7500                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
7501                         const gchar *p;
7502                         MonoMethodSignature *sig;
7503
7504                         if (!attr->ctor || attr->ctor->klass != klass)
7505                                 continue;
7506                         /* Decode the attribute. See reflection.c */
7507                         p = (const char*)attr->data;
7508                         g_assert (read16 (p) == 0x0001);
7509                         p += 2;
7510
7511                         // FIXME: Support named parameters
7512                         sig = mono_method_signature (attr->ctor);
7513                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
7514                                 continue;
7515                         /* Two boolean arguments */
7516                         p ++;
7517                         val = *p;
7518                 }
7519                 mono_custom_attrs_free (attrs);
7520         }
7521
7522         ass->jit_optimizer_disabled = val;
7523         mono_memory_barrier ();
7524         ass->jit_optimizer_disabled_inited = TRUE;
7525
7526         return val;
7527 }
7528
7529 static gboolean
7530 is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig, int call_opcode)
7531 {
7532         gboolean supported_tail_call;
7533         int i;
7534
7535 #ifdef MONO_ARCH_HAVE_OP_TAIL_CALL
7536         supported_tail_call = mono_arch_tail_call_supported (cfg, mono_method_signature (method), mono_method_signature (cmethod));
7537 #else
7538         supported_tail_call = mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod)) && !MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->ret);
7539 #endif
7540
7541         for (i = 0; i < fsig->param_count; ++i) {
7542                 if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
7543                         /* These can point to the current method's stack */
7544                         supported_tail_call = FALSE;
7545         }
7546         if (fsig->hasthis && cmethod->klass->valuetype)
7547                 /* this might point to the current method's stack */
7548                 supported_tail_call = FALSE;
7549         if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
7550                 supported_tail_call = FALSE;
7551         if (cfg->method->save_lmf)
7552                 supported_tail_call = FALSE;
7553         if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
7554                 supported_tail_call = FALSE;
7555         if (call_opcode != CEE_CALL)
7556                 supported_tail_call = FALSE;
7557
7558         /* Debugging support */
7559 #if 0
7560         if (supported_tail_call) {
7561                 if (!mono_debug_count ())
7562                         supported_tail_call = FALSE;
7563         }
7564 #endif
7565
7566         return supported_tail_call;
7567 }
7568
7569 /* the JIT intercepts ldflda instructions to the tlsdata field in ThreadLocal<T> and redirects
7570  * it to the thread local value based on the tls_offset field. Every other kind of access to
7571  * the field causes an assert.
7572  */
7573 static gboolean
7574 is_magic_tls_access (MonoClassField *field)
7575 {
7576         if (strcmp (field->name, "tlsdata"))
7577                 return FALSE;
7578         if (strcmp (field->parent->name, "ThreadLocal`1"))
7579                 return FALSE;
7580         return field->parent->image == mono_defaults.corlib;
7581 }
7582
7583 /* emits the code needed to access a managed tls var (like ThreadStatic)
7584  * with the value of the tls offset in offset_reg. thread_ins represents the MonoInternalThread
7585  * pointer for the current thread.
7586  * Returns the MonoInst* representing the address of the tls var.
7587  */
7588 static MonoInst*
7589 emit_managed_static_data_access (MonoCompile *cfg, MonoInst *thread_ins, int offset_reg)
7590 {
7591         MonoInst *addr;
7592         int static_data_reg, array_reg, dreg;
7593         int offset2_reg, idx_reg;
7594         // inlined access to the tls data
7595         // idx = (offset >> 24) - 1;
7596         // return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
7597         static_data_reg = alloc_ireg (cfg);
7598         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
7599         idx_reg = alloc_ireg (cfg);
7600         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_IMM, idx_reg, offset_reg, 24);
7601         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, idx_reg, idx_reg, 1);
7602         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
7603         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
7604         array_reg = alloc_ireg (cfg);
7605         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
7606         offset2_reg = alloc_ireg (cfg);
7607         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset_reg, 0xffffff);
7608         dreg = alloc_ireg (cfg);
7609         EMIT_NEW_BIALU (cfg, addr, OP_PADD, dreg, array_reg, offset2_reg);
7610         return addr;
7611 }
7612
7613 /*
7614  * redirect access to the tlsdata field to the tls var given by the tls_offset field.
7615  * this address is cached per-method in cached_tls_addr.
7616  */
7617 static MonoInst*
7618 create_magic_tls_access (MonoCompile *cfg, MonoClassField *tls_field, MonoInst **cached_tls_addr, MonoInst *thread_local)
7619 {
7620         MonoInst *load, *addr, *temp, *store, *thread_ins;
7621         MonoClassField *offset_field;
7622
7623         if (*cached_tls_addr) {
7624                 EMIT_NEW_TEMPLOAD (cfg, addr, (*cached_tls_addr)->inst_c0);
7625                 return addr;
7626         }
7627         thread_ins = mono_get_thread_intrinsic (cfg);
7628         offset_field = mono_class_get_field_from_name (tls_field->parent, "tls_offset");
7629
7630         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, offset_field->type, thread_local->dreg, offset_field->offset);
7631         if (thread_ins) {
7632                 MONO_ADD_INS (cfg->cbb, thread_ins);
7633         } else {
7634                 MonoMethod *thread_method;
7635                 thread_method = mono_class_get_method_from_name (mono_get_thread_class(), "CurrentInternalThread_internal", 0);
7636                 thread_ins = mono_emit_method_call (cfg, thread_method, NULL, NULL);
7637         }
7638         addr = emit_managed_static_data_access (cfg, thread_ins, load->dreg);
7639         addr->klass = mono_class_from_mono_type (tls_field->type);
7640         addr->type = STACK_MP;
7641         *cached_tls_addr = temp = mono_compile_create_var (cfg, type_from_stack_type (addr), OP_LOCAL);
7642         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, addr);
7643
7644         EMIT_NEW_TEMPLOAD (cfg, addr, temp->inst_c0);
7645         return addr;
7646 }
7647
7648 /*
7649  * handle_ctor_call:
7650  *
7651  *   Handle calls made to ctors from NEWOBJ opcodes.
7652  *
7653  *   REF_BBLOCK will point to the current bblock after the call.
7654  */
7655 static void
7656 handle_ctor_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used,
7657                                   MonoInst **sp, guint8 *ip, MonoBasicBlock **ref_bblock, int *inline_costs)
7658 {
7659         MonoInst *vtable_arg = NULL, *callvirt_this_arg = NULL, *ins;
7660         MonoBasicBlock *bblock = *ref_bblock;
7661
7662         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
7663                                         mono_method_is_generic_sharable (cmethod, TRUE)) {
7664                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
7665                         mono_class_vtable (cfg->domain, cmethod->klass);
7666                         CHECK_TYPELOAD (cmethod->klass);
7667
7668                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
7669                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
7670                 } else {
7671                         if (context_used) {
7672                                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
7673                                                                                                    cmethod->klass, MONO_RGCTX_INFO_VTABLE);
7674                         } else {
7675                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
7676
7677                                 CHECK_TYPELOAD (cmethod->klass);
7678                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
7679                         }
7680                 }
7681         }
7682
7683         /* Avoid virtual calls to ctors if possible */
7684         if (mono_class_is_marshalbyref (cmethod->klass))
7685                 callvirt_this_arg = sp [0];
7686
7687         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
7688                 g_assert (MONO_TYPE_IS_VOID (fsig->ret));
7689                 CHECK_CFG_EXCEPTION;
7690         } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
7691                            mono_method_check_inlining (cfg, cmethod) &&
7692                            !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE)) {
7693                 int costs;
7694
7695                 if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, FALSE, &bblock))) {
7696                         cfg->real_offset += 5;
7697
7698                         *inline_costs += costs - 5;
7699                         *ref_bblock = bblock;
7700                 } else {
7701                         INLINE_FAILURE ("inline failure");
7702                         // FIXME-VT: Clean this up
7703                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))
7704                                 GSHAREDVT_FAILURE(*ip);
7705                         mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
7706                 }
7707         } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig)) {
7708                 MonoInst *addr;
7709
7710                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
7711                 mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
7712         } else if (context_used &&
7713                            ((!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
7714                                  !mono_class_generic_sharing_enabled (cmethod->klass)) || cfg->gsharedvt)) {
7715                 MonoInst *cmethod_addr;
7716
7717                 /* Generic calls made out of gsharedvt methods cannot be patched, so use an indirect call */
7718
7719                 cmethod_addr = emit_get_rgctx_method (cfg, context_used,
7720                                                                                           cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
7721
7722                 mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
7723         } else {
7724                 INLINE_FAILURE ("ctor call");
7725                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
7726                                                                                   callvirt_this_arg, NULL, vtable_arg);
7727         }
7728  exception_exit:
7729         return;
7730 }
7731
7732 /*
7733  * mono_method_to_ir:
7734  *
7735  *   Translate the .net IL into linear IR.
7736  */
7737 int
7738 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
7739                    MonoInst *return_var, MonoInst **inline_args, 
7740                    guint inline_offset, gboolean is_virtual_call)
7741 {
7742         MonoError error;
7743         MonoInst *ins, **sp, **stack_start;
7744         MonoBasicBlock *bblock, *tblock = NULL, *init_localsbb = NULL;
7745         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
7746         MonoMethod *cmethod, *method_definition;
7747         MonoInst **arg_array;
7748         MonoMethodHeader *header;
7749         MonoImage *image;
7750         guint32 token, ins_flag;
7751         MonoClass *klass;
7752         MonoClass *constrained_class = NULL;
7753         unsigned char *ip, *end, *target, *err_pos;
7754         MonoMethodSignature *sig;
7755         MonoGenericContext *generic_context = NULL;
7756         MonoGenericContainer *generic_container = NULL;
7757         MonoType **param_types;
7758         int i, n, start_new_bblock, dreg;
7759         int num_calls = 0, inline_costs = 0;
7760         int breakpoint_id = 0;
7761         guint num_args;
7762         MonoBoolean security, pinvoke;
7763         MonoSecurityManager* secman = NULL;
7764         MonoDeclSecurityActions actions;
7765         GSList *class_inits = NULL;
7766         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
7767         int context_used;
7768         gboolean init_locals, seq_points, skip_dead_blocks;
7769         gboolean sym_seq_points = FALSE;
7770         MonoInst *cached_tls_addr = NULL;
7771         MonoDebugMethodInfo *minfo;
7772         MonoBitSet *seq_point_locs = NULL;
7773         MonoBitSet *seq_point_set_locs = NULL;
7774
7775         cfg->disable_inline = is_jit_optimizer_disabled (method);
7776
7777         /* serialization and xdomain stuff may need access to private fields and methods */
7778         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
7779         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
7780         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
7781         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
7782         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
7783         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
7784
7785         dont_verify |= mono_security_smcs_hack_enabled ();
7786
7787         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
7788         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
7789         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
7790         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
7791         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
7792
7793         image = method->klass->image;
7794         header = mono_method_get_header (method);
7795         if (!header) {
7796                 MonoLoaderError *error;
7797
7798                 if ((error = mono_loader_get_last_error ())) {
7799                         mono_cfg_set_exception (cfg, error->exception_type);
7800                 } else {
7801                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
7802                         cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
7803                 }
7804                 goto exception_exit;
7805         }
7806         generic_container = mono_method_get_generic_container (method);
7807         sig = mono_method_signature (method);
7808         num_args = sig->hasthis + sig->param_count;
7809         ip = (unsigned char*)header->code;
7810         cfg->cil_start = ip;
7811         end = ip + header->code_size;
7812         cfg->stat_cil_code_size += header->code_size;
7813
7814         seq_points = cfg->gen_seq_points && cfg->method == method;
7815
7816         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
7817                 /* We could hit a seq point before attaching to the JIT (#8338) */
7818                 seq_points = FALSE;
7819         }
7820
7821         if (cfg->gen_sdb_seq_points && cfg->method == method) {
7822                 minfo = mono_debug_lookup_method (method);
7823                 if (minfo) {
7824                         int i, n_il_offsets;
7825                         int *il_offsets;
7826                         int *line_numbers;
7827
7828                         mono_debug_symfile_get_line_numbers_full (minfo, NULL, NULL, &n_il_offsets, &il_offsets, &line_numbers, NULL, NULL, NULL, NULL);
7829                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7830                         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);
7831                         sym_seq_points = TRUE;
7832                         for (i = 0; i < n_il_offsets; ++i) {
7833                                 if (il_offsets [i] < header->code_size)
7834                                         mono_bitset_set_fast (seq_point_locs, il_offsets [i]);
7835                         }
7836                         g_free (il_offsets);
7837                         g_free (line_numbers);
7838                 } else if (!method->wrapper_type && !method->dynamic && mono_debug_image_has_debug_info (method->klass->image)) {
7839                         /* Methods without line number info like auto-generated property accessors */
7840                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7841                         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);
7842                         sym_seq_points = TRUE;
7843                 }
7844         }
7845
7846         /* 
7847          * Methods without init_locals set could cause asserts in various passes
7848          * (#497220). To work around this, we emit dummy initialization opcodes
7849          * (OP_DUMMY_ICONST etc.) which generate no code. These are only supported
7850          * on some platforms.
7851          */
7852         if ((cfg->opt & MONO_OPT_UNSAFE) && ARCH_HAVE_DUMMY_INIT)
7853                 init_locals = header->init_locals;
7854         else
7855                 init_locals = TRUE;
7856
7857         method_definition = method;
7858         while (method_definition->is_inflated) {
7859                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
7860                 method_definition = imethod->declaring;
7861         }
7862
7863         /* SkipVerification is not allowed if core-clr is enabled */
7864         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
7865                 dont_verify = TRUE;
7866                 dont_verify_stloc = TRUE;
7867         }
7868
7869         if (sig->is_inflated)
7870                 generic_context = mono_method_get_context (method);
7871         else if (generic_container)
7872                 generic_context = &generic_container->context;
7873         cfg->generic_context = generic_context;
7874
7875         if (!cfg->generic_sharing_context)
7876                 g_assert (!sig->has_type_parameters);
7877
7878         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
7879                 g_assert (method->is_inflated);
7880                 g_assert (mono_method_get_context (method)->method_inst);
7881         }
7882         if (method->is_inflated && mono_method_get_context (method)->method_inst)
7883                 g_assert (sig->generic_param_count);
7884
7885         if (cfg->method == method) {
7886                 cfg->real_offset = 0;
7887         } else {
7888                 cfg->real_offset = inline_offset;
7889         }
7890
7891         cfg->cil_offset_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
7892         cfg->cil_offset_to_bb_len = header->code_size;
7893
7894         cfg->current_method = method;
7895
7896         if (cfg->verbose_level > 2)
7897                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
7898
7899         param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
7900         if (sig->hasthis)
7901                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
7902         for (n = 0; n < sig->param_count; ++n)
7903                 param_types [n + sig->hasthis] = sig->params [n];
7904         cfg->arg_types = param_types;
7905
7906         cfg->dont_inline = g_list_prepend (cfg->dont_inline, method);
7907         if (cfg->method == method) {
7908
7909                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
7910                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
7911
7912                 /* ENTRY BLOCK */
7913                 NEW_BBLOCK (cfg, start_bblock);
7914                 cfg->bb_entry = start_bblock;
7915                 start_bblock->cil_code = NULL;
7916                 start_bblock->cil_length = 0;
7917 #if defined(__native_client_codegen__)
7918                 MONO_INST_NEW (cfg, ins, OP_NACL_GC_SAFE_POINT);
7919                 ins->dreg = alloc_dreg (cfg, STACK_I4);
7920                 MONO_ADD_INS (start_bblock, ins);
7921 #endif
7922
7923                 /* EXIT BLOCK */
7924                 NEW_BBLOCK (cfg, end_bblock);
7925                 cfg->bb_exit = end_bblock;
7926                 end_bblock->cil_code = NULL;
7927                 end_bblock->cil_length = 0;
7928                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
7929                 g_assert (cfg->num_bblocks == 2);
7930
7931                 arg_array = cfg->args;
7932
7933                 if (header->num_clauses) {
7934                         cfg->spvars = g_hash_table_new (NULL, NULL);
7935                         cfg->exvars = g_hash_table_new (NULL, NULL);
7936                 }
7937                 /* handle exception clauses */
7938                 for (i = 0; i < header->num_clauses; ++i) {
7939                         MonoBasicBlock *try_bb;
7940                         MonoExceptionClause *clause = &header->clauses [i];
7941                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
7942                         try_bb->real_offset = clause->try_offset;
7943                         try_bb->try_start = TRUE;
7944                         try_bb->region = ((i + 1) << 8) | clause->flags;
7945                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
7946                         tblock->real_offset = clause->handler_offset;
7947                         tblock->flags |= BB_EXCEPTION_HANDLER;
7948
7949                         /*
7950                          * Linking the try block with the EH block hinders inlining as we won't be able to 
7951                          * merge the bblocks from inlining and produce an artificial hole for no good reason.
7952                          */
7953                         if (COMPILE_LLVM (cfg))
7954                                 link_bblock (cfg, try_bb, tblock);
7955
7956                         if (*(ip + clause->handler_offset) == CEE_POP)
7957                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
7958
7959                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
7960                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
7961                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
7962                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
7963                                 MONO_ADD_INS (tblock, ins);
7964
7965                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY) {
7966                                         /* finally clauses already have a seq point */
7967                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
7968                                         MONO_ADD_INS (tblock, ins);
7969                                 }
7970
7971                                 /* todo: is a fault block unsafe to optimize? */
7972                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
7973                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
7974                         }
7975
7976
7977                         /*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);
7978                           while (p < end) {
7979                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
7980                           }*/
7981                         /* catch and filter blocks get the exception object on the stack */
7982                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
7983                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7984                                 MonoInst *dummy_use;
7985
7986                                 /* mostly like handle_stack_args (), but just sets the input args */
7987                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
7988                                 tblock->in_scount = 1;
7989                                 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7990                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7991
7992                                 /* 
7993                                  * Add a dummy use for the exvar so its liveness info will be
7994                                  * correct.
7995                                  */
7996                                 cfg->cbb = tblock;
7997                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
7998                                 
7999                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8000                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
8001                                         tblock->flags |= BB_EXCEPTION_HANDLER;
8002                                         tblock->real_offset = clause->data.filter_offset;
8003                                         tblock->in_scount = 1;
8004                                         tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
8005                                         /* The filter block shares the exvar with the handler block */
8006                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
8007                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
8008                                         MONO_ADD_INS (tblock, ins);
8009                                 }
8010                         }
8011
8012                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
8013                                         clause->data.catch_class &&
8014                                         cfg->generic_sharing_context &&
8015                                         mono_class_check_context_used (clause->data.catch_class)) {
8016                                 /*
8017                                  * In shared generic code with catch
8018                                  * clauses containing type variables
8019                                  * the exception handling code has to
8020                                  * be able to get to the rgctx.
8021                                  * Therefore we have to make sure that
8022                                  * the vtable/mrgctx argument (for
8023                                  * static or generic methods) or the
8024                                  * "this" argument (for non-static
8025                                  * methods) are live.
8026                                  */
8027                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8028                                                 mini_method_get_context (method)->method_inst ||
8029                                                 method->klass->valuetype) {
8030                                         mono_get_vtable_var (cfg);
8031                                 } else {
8032                                         MonoInst *dummy_use;
8033
8034                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
8035                                 }
8036                         }
8037                 }
8038         } else {
8039                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
8040                 cfg->cbb = start_bblock;
8041                 cfg->args = arg_array;
8042                 mono_save_args (cfg, sig, inline_args);
8043         }
8044
8045         /* FIRST CODE BLOCK */
8046         NEW_BBLOCK (cfg, bblock);
8047         bblock->cil_code = ip;
8048         cfg->cbb = bblock;
8049         cfg->ip = ip;
8050
8051         ADD_BBLOCK (cfg, bblock);
8052
8053         if (cfg->method == method) {
8054                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
8055                 if (breakpoint_id) {
8056                         MONO_INST_NEW (cfg, ins, OP_BREAK);
8057                         MONO_ADD_INS (bblock, ins);
8058                 }
8059         }
8060
8061         if (mono_security_cas_enabled ())
8062                 secman = mono_security_manager_get_methods ();
8063
8064         security = (secman && mono_security_method_has_declsec (method));
8065         /* at this point having security doesn't mean we have any code to generate */
8066         if (security && (cfg->method == method)) {
8067                 /* Only Demand, NonCasDemand and DemandChoice requires code generation.
8068                  * And we do not want to enter the next section (with allocation) if we
8069                  * have nothing to generate */
8070                 security = mono_declsec_get_demands (method, &actions);
8071         }
8072
8073         /* we must Demand SecurityPermission.Unmanaged before P/Invoking */
8074         pinvoke = (secman && (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE));
8075         if (pinvoke) {
8076                 MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
8077                 if (wrapped && (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
8078                         MonoCustomAttrInfo* custom = mono_custom_attrs_from_method (wrapped);
8079
8080                         /* unless the method or it's class has the [SuppressUnmanagedCodeSecurity] attribute */
8081                         if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
8082                                 pinvoke = FALSE;
8083                         }
8084                         if (custom)
8085                                 mono_custom_attrs_free (custom);
8086
8087                         if (pinvoke) {
8088                                 custom = mono_custom_attrs_from_class (wrapped->klass);
8089                                 if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
8090                                         pinvoke = FALSE;
8091                                 }
8092                                 if (custom)
8093                                         mono_custom_attrs_free (custom);
8094                         }
8095                 } else {
8096                         /* not a P/Invoke after all */
8097                         pinvoke = FALSE;
8098                 }
8099         }
8100         
8101         /* we use a separate basic block for the initialization code */
8102         NEW_BBLOCK (cfg, init_localsbb);
8103         cfg->bb_init = init_localsbb;
8104         init_localsbb->real_offset = cfg->real_offset;
8105         start_bblock->next_bb = init_localsbb;
8106         init_localsbb->next_bb = bblock;
8107         link_bblock (cfg, start_bblock, init_localsbb);
8108         link_bblock (cfg, init_localsbb, bblock);
8109                 
8110         cfg->cbb = init_localsbb;
8111
8112         if (cfg->gsharedvt && cfg->method == method) {
8113                 MonoGSharedVtMethodInfo *info;
8114                 MonoInst *var, *locals_var;
8115                 int dreg;
8116
8117                 info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
8118                 info->method = cfg->method;
8119                 info->count_entries = 16;
8120                 info->entries = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
8121                 cfg->gsharedvt_info = info;
8122
8123                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8124                 /* prevent it from being register allocated */
8125                 //var->flags |= MONO_INST_VOLATILE;
8126                 cfg->gsharedvt_info_var = var;
8127
8128                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
8129                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
8130
8131                 /* Allocate locals */
8132                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8133                 /* prevent it from being register allocated */
8134                 //locals_var->flags |= MONO_INST_VOLATILE;
8135                 cfg->gsharedvt_locals_var = locals_var;
8136
8137                 dreg = alloc_ireg (cfg);
8138                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
8139
8140                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
8141                 ins->dreg = locals_var->dreg;
8142                 ins->sreg1 = dreg;
8143                 MONO_ADD_INS (cfg->cbb, ins);
8144                 cfg->gsharedvt_locals_var_ins = ins;
8145                 
8146                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
8147                 /*
8148                 if (init_locals)
8149                         ins->flags |= MONO_INST_INIT;
8150                 */
8151         }
8152
8153         /* at this point we know, if security is TRUE, that some code needs to be generated */
8154         if (security && (cfg->method == method)) {
8155                 MonoInst *args [2];
8156
8157                 cfg->stat_cas_demand_generation++;
8158
8159                 if (actions.demand.blob) {
8160                         /* Add code for SecurityAction.Demand */
8161                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.demand);
8162                         EMIT_NEW_ICONST (cfg, args [1], actions.demand.size);
8163                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
8164                         mono_emit_method_call (cfg, secman->demand, args, NULL);
8165                 }
8166                 if (actions.noncasdemand.blob) {
8167                         /* CLR 1.x uses a .noncasdemand (but 2.x doesn't) */
8168                         /* For Mono we re-route non-CAS Demand to Demand (as the managed code must deal with it anyway) */
8169                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.noncasdemand);
8170                         EMIT_NEW_ICONST (cfg, args [1], actions.noncasdemand.size);
8171                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
8172                         mono_emit_method_call (cfg, secman->demand, args, NULL);
8173                 }
8174                 if (actions.demandchoice.blob) {
8175                         /* New in 2.0, Demand must succeed for one of the permissions (i.e. not all) */
8176                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.demandchoice);
8177                         EMIT_NEW_ICONST (cfg, args [1], actions.demandchoice.size);
8178                         /* Calls static void SecurityManager.InternalDemandChoice (byte* permissions, int size); */
8179                         mono_emit_method_call (cfg, secman->demandchoice, args, NULL);
8180                 }
8181         }
8182
8183         /* we must Demand SecurityPermission.Unmanaged before p/invoking */
8184         if (pinvoke) {
8185                 mono_emit_method_call (cfg, secman->demandunmanaged, NULL, NULL);
8186         }
8187
8188         if (mono_security_core_clr_enabled ()) {
8189                 /* check if this is native code, e.g. an icall or a p/invoke */
8190                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
8191                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
8192                         if (wrapped) {
8193                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
8194                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
8195
8196                                 /* if this ia a native call then it can only be JITted from platform code */
8197                                 if ((icall || pinvk) && method->klass && method->klass->image) {
8198                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
8199                                                 MonoException *ex = icall ? mono_get_exception_security () : 
8200                                                         mono_get_exception_method_access ();
8201                                                 emit_throw_exception (cfg, ex);
8202                                         }
8203                                 }
8204                         }
8205                 }
8206         }
8207
8208         CHECK_CFG_EXCEPTION;
8209
8210         if (header->code_size == 0)
8211                 UNVERIFIED;
8212
8213         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
8214                 ip = err_pos;
8215                 UNVERIFIED;
8216         }
8217
8218         if (cfg->method == method)
8219                 mono_debug_init_method (cfg, bblock, breakpoint_id);
8220
8221         for (n = 0; n < header->num_locals; ++n) {
8222                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
8223                         UNVERIFIED;
8224         }
8225         class_inits = NULL;
8226
8227         /* We force the vtable variable here for all shared methods
8228            for the possibility that they might show up in a stack
8229            trace where their exact instantiation is needed. */
8230         if (cfg->generic_sharing_context && method == cfg->method) {
8231                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8232                                 mini_method_get_context (method)->method_inst ||
8233                                 method->klass->valuetype) {
8234                         mono_get_vtable_var (cfg);
8235                 } else {
8236                         /* FIXME: Is there a better way to do this?
8237                            We need the variable live for the duration
8238                            of the whole method. */
8239                         cfg->args [0]->flags |= MONO_INST_VOLATILE;
8240                 }
8241         }
8242
8243         /* add a check for this != NULL to inlined methods */
8244         if (is_virtual_call) {
8245                 MonoInst *arg_ins;
8246
8247                 NEW_ARGLOAD (cfg, arg_ins, 0);
8248                 MONO_ADD_INS (cfg->cbb, arg_ins);
8249                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
8250         }
8251
8252         skip_dead_blocks = !dont_verify;
8253         if (skip_dead_blocks) {
8254                 original_bb = bb = mono_basic_block_split (method, &cfg->error);
8255                 CHECK_CFG_ERROR;
8256                 g_assert (bb);
8257         }
8258
8259         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
8260         stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
8261
8262         ins_flag = 0;
8263         start_new_bblock = 0;
8264         cfg->cbb = bblock;
8265         while (ip < end) {
8266                 if (cfg->method == method)
8267                         cfg->real_offset = ip - header->code;
8268                 else
8269                         cfg->real_offset = inline_offset;
8270                 cfg->ip = ip;
8271
8272                 context_used = 0;
8273                 
8274                 if (start_new_bblock) {
8275                         bblock->cil_length = ip - bblock->cil_code;
8276                         if (start_new_bblock == 2) {
8277                                 g_assert (ip == tblock->cil_code);
8278                         } else {
8279                                 GET_BBLOCK (cfg, tblock, ip);
8280                         }
8281                         bblock->next_bb = tblock;
8282                         bblock = tblock;
8283                         cfg->cbb = bblock;
8284                         start_new_bblock = 0;
8285                         for (i = 0; i < bblock->in_scount; ++i) {
8286                                 if (cfg->verbose_level > 3)
8287                                         printf ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                            
8288                                 EMIT_NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
8289                                 *sp++ = ins;
8290                         }
8291                         if (class_inits)
8292                                 g_slist_free (class_inits);
8293                         class_inits = NULL;
8294                 } else {
8295                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != bblock)) {
8296                                 link_bblock (cfg, bblock, tblock);
8297                                 if (sp != stack_start) {
8298                                         handle_stack_args (cfg, stack_start, sp - stack_start);
8299                                         sp = stack_start;
8300                                         CHECK_UNVERIFIABLE (cfg);
8301                                 }
8302                                 bblock->next_bb = tblock;
8303                                 bblock = tblock;
8304                                 cfg->cbb = bblock;
8305                                 for (i = 0; i < bblock->in_scount; ++i) {
8306                                         if (cfg->verbose_level > 3)
8307                                                 printf ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                            
8308                                         EMIT_NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
8309                                         *sp++ = ins;
8310                                 }
8311                                 g_slist_free (class_inits);
8312                                 class_inits = NULL;
8313                         }
8314                 }
8315
8316                 if (skip_dead_blocks) {
8317                         int ip_offset = ip - header->code;
8318
8319                         if (ip_offset == bb->end)
8320                                 bb = bb->next;
8321
8322                         if (bb->dead) {
8323                                 int op_size = mono_opcode_size (ip, end);
8324                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
8325
8326                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
8327
8328                                 if (ip_offset + op_size == bb->end) {
8329                                         MONO_INST_NEW (cfg, ins, OP_NOP);
8330                                         MONO_ADD_INS (bblock, ins);
8331                                         start_new_bblock = 1;
8332                                 }
8333
8334                                 ip += op_size;
8335                                 continue;
8336                         }
8337                 }
8338                 /*
8339                  * Sequence points are points where the debugger can place a breakpoint.
8340                  * Currently, we generate these automatically at points where the IL
8341                  * stack is empty.
8342                  */
8343                 if (seq_points && ((!sym_seq_points && (sp == stack_start)) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
8344                         /*
8345                          * Make methods interruptable at the beginning, and at the targets of
8346                          * backward branches.
8347                          * Also, do this at the start of every bblock in methods with clauses too,
8348                          * to be able to handle instructions with inprecise control flow like
8349                          * throw/endfinally.
8350                          * Backward branches are handled at the end of method-to-ir ().
8351                          */
8352                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
8353
8354                         /* Avoid sequence points on empty IL like .volatile */
8355                         // FIXME: Enable this
8356                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
8357                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
8358                         if (sp != stack_start)
8359                                 ins->flags |= MONO_INST_NONEMPTY_STACK;
8360                         MONO_ADD_INS (cfg->cbb, ins);
8361
8362                         if (sym_seq_points)
8363                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
8364                 }
8365
8366                 bblock->real_offset = cfg->real_offset;
8367
8368                 if ((cfg->method == method) && cfg->coverage_info) {
8369                         guint32 cil_offset = ip - header->code;
8370                         cfg->coverage_info->data [cil_offset].cil_code = ip;
8371
8372                         /* TODO: Use an increment here */
8373 #if defined(TARGET_X86)
8374                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
8375                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
8376                         ins->inst_imm = 1;
8377                         MONO_ADD_INS (cfg->cbb, ins);
8378 #else
8379                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
8380                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
8381 #endif
8382                 }
8383
8384                 if (cfg->verbose_level > 3)
8385                         printf ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
8386
8387                 switch (*ip) {
8388                 case CEE_NOP:
8389                         if (seq_points && !sym_seq_points && sp != stack_start) {
8390                                 /*
8391                                  * The C# compiler uses these nops to notify the JIT that it should
8392                                  * insert seq points.
8393                                  */
8394                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
8395                                 MONO_ADD_INS (cfg->cbb, ins);
8396                         }
8397                         if (cfg->keep_cil_nops)
8398                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
8399                         else
8400                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8401                         ip++;
8402                         MONO_ADD_INS (bblock, ins);
8403                         break;
8404                 case CEE_BREAK:
8405                         if (should_insert_brekpoint (cfg->method)) {
8406                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
8407                         } else {
8408                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8409                         }
8410                         ip++;
8411                         MONO_ADD_INS (bblock, ins);
8412                         break;
8413                 case CEE_LDARG_0:
8414                 case CEE_LDARG_1:
8415                 case CEE_LDARG_2:
8416                 case CEE_LDARG_3:
8417                         CHECK_STACK_OVF (1);
8418                         n = (*ip)-CEE_LDARG_0;
8419                         CHECK_ARG (n);
8420                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8421                         ip++;
8422                         *sp++ = ins;
8423                         break;
8424                 case CEE_LDLOC_0:
8425                 case CEE_LDLOC_1:
8426                 case CEE_LDLOC_2:
8427                 case CEE_LDLOC_3:
8428                         CHECK_STACK_OVF (1);
8429                         n = (*ip)-CEE_LDLOC_0;
8430                         CHECK_LOCAL (n);
8431                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8432                         ip++;
8433                         *sp++ = ins;
8434                         break;
8435                 case CEE_STLOC_0:
8436                 case CEE_STLOC_1:
8437                 case CEE_STLOC_2:
8438                 case CEE_STLOC_3: {
8439                         CHECK_STACK (1);
8440                         n = (*ip)-CEE_STLOC_0;
8441                         CHECK_LOCAL (n);
8442                         --sp;
8443                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
8444                                 UNVERIFIED;
8445                         emit_stloc_ir (cfg, sp, header, n);
8446                         ++ip;
8447                         inline_costs += 1;
8448                         break;
8449                         }
8450                 case CEE_LDARG_S:
8451                         CHECK_OPSIZE (2);
8452                         CHECK_STACK_OVF (1);
8453                         n = ip [1];
8454                         CHECK_ARG (n);
8455                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8456                         *sp++ = ins;
8457                         ip += 2;
8458                         break;
8459                 case CEE_LDARGA_S:
8460                         CHECK_OPSIZE (2);
8461                         CHECK_STACK_OVF (1);
8462                         n = ip [1];
8463                         CHECK_ARG (n);
8464                         NEW_ARGLOADA (cfg, ins, n);
8465                         MONO_ADD_INS (cfg->cbb, ins);
8466                         *sp++ = ins;
8467                         ip += 2;
8468                         break;
8469                 case CEE_STARG_S:
8470                         CHECK_OPSIZE (2);
8471                         CHECK_STACK (1);
8472                         --sp;
8473                         n = ip [1];
8474                         CHECK_ARG (n);
8475                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
8476                                 UNVERIFIED;
8477                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
8478                         ip += 2;
8479                         break;
8480                 case CEE_LDLOC_S:
8481                         CHECK_OPSIZE (2);
8482                         CHECK_STACK_OVF (1);
8483                         n = ip [1];
8484                         CHECK_LOCAL (n);
8485                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8486                         *sp++ = ins;
8487                         ip += 2;
8488                         break;
8489                 case CEE_LDLOCA_S: {
8490                         unsigned char *tmp_ip;
8491                         CHECK_OPSIZE (2);
8492                         CHECK_STACK_OVF (1);
8493                         CHECK_LOCAL (ip [1]);
8494
8495                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
8496                                 ip = tmp_ip;
8497                                 inline_costs += 1;
8498                                 break;
8499                         }
8500
8501                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
8502                         *sp++ = ins;
8503                         ip += 2;
8504                         break;
8505                 }
8506                 case CEE_STLOC_S:
8507                         CHECK_OPSIZE (2);
8508                         CHECK_STACK (1);
8509                         --sp;
8510                         CHECK_LOCAL (ip [1]);
8511                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
8512                                 UNVERIFIED;
8513                         emit_stloc_ir (cfg, sp, header, ip [1]);
8514                         ip += 2;
8515                         inline_costs += 1;
8516                         break;
8517                 case CEE_LDNULL:
8518                         CHECK_STACK_OVF (1);
8519                         EMIT_NEW_PCONST (cfg, ins, NULL);
8520                         ins->type = STACK_OBJ;
8521                         ++ip;
8522                         *sp++ = ins;
8523                         break;
8524                 case CEE_LDC_I4_M1:
8525                         CHECK_STACK_OVF (1);
8526                         EMIT_NEW_ICONST (cfg, ins, -1);
8527                         ++ip;
8528                         *sp++ = ins;
8529                         break;
8530                 case CEE_LDC_I4_0:
8531                 case CEE_LDC_I4_1:
8532                 case CEE_LDC_I4_2:
8533                 case CEE_LDC_I4_3:
8534                 case CEE_LDC_I4_4:
8535                 case CEE_LDC_I4_5:
8536                 case CEE_LDC_I4_6:
8537                 case CEE_LDC_I4_7:
8538                 case CEE_LDC_I4_8:
8539                         CHECK_STACK_OVF (1);
8540                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
8541                         ++ip;
8542                         *sp++ = ins;
8543                         break;
8544                 case CEE_LDC_I4_S:
8545                         CHECK_OPSIZE (2);
8546                         CHECK_STACK_OVF (1);
8547                         ++ip;
8548                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
8549                         ++ip;
8550                         *sp++ = ins;
8551                         break;
8552                 case CEE_LDC_I4:
8553                         CHECK_OPSIZE (5);
8554                         CHECK_STACK_OVF (1);
8555                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
8556                         ip += 5;
8557                         *sp++ = ins;
8558                         break;
8559                 case CEE_LDC_I8:
8560                         CHECK_OPSIZE (9);
8561                         CHECK_STACK_OVF (1);
8562                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
8563                         ins->type = STACK_I8;
8564                         ins->dreg = alloc_dreg (cfg, STACK_I8);
8565                         ++ip;
8566                         ins->inst_l = (gint64)read64 (ip);
8567                         MONO_ADD_INS (bblock, ins);
8568                         ip += 8;
8569                         *sp++ = ins;
8570                         break;
8571                 case CEE_LDC_R4: {
8572                         float *f;
8573                         gboolean use_aotconst = FALSE;
8574
8575 #ifdef TARGET_POWERPC
8576                         /* FIXME: Clean this up */
8577                         if (cfg->compile_aot)
8578                                 use_aotconst = TRUE;
8579 #endif
8580
8581                         /* FIXME: we should really allocate this only late in the compilation process */
8582                         f = mono_domain_alloc (cfg->domain, sizeof (float));
8583                         CHECK_OPSIZE (5);
8584                         CHECK_STACK_OVF (1);
8585
8586                         if (use_aotconst) {
8587                                 MonoInst *cons;
8588                                 int dreg;
8589
8590                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
8591
8592                                 dreg = alloc_freg (cfg);
8593                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
8594                                 ins->type = cfg->r4_stack_type;
8595                         } else {
8596                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
8597                                 ins->type = cfg->r4_stack_type;
8598                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8599                                 ins->inst_p0 = f;
8600                                 MONO_ADD_INS (bblock, ins);
8601                         }
8602                         ++ip;
8603                         readr4 (ip, f);
8604                         ip += 4;
8605                         *sp++ = ins;                    
8606                         break;
8607                 }
8608                 case CEE_LDC_R8: {
8609                         double *d;
8610                         gboolean use_aotconst = FALSE;
8611
8612 #ifdef TARGET_POWERPC
8613                         /* FIXME: Clean this up */
8614                         if (cfg->compile_aot)
8615                                 use_aotconst = TRUE;
8616 #endif
8617
8618                         /* FIXME: we should really allocate this only late in the compilation process */
8619                         d = mono_domain_alloc (cfg->domain, sizeof (double));
8620                         CHECK_OPSIZE (9);
8621                         CHECK_STACK_OVF (1);
8622
8623                         if (use_aotconst) {
8624                                 MonoInst *cons;
8625                                 int dreg;
8626
8627                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
8628
8629                                 dreg = alloc_freg (cfg);
8630                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
8631                                 ins->type = STACK_R8;
8632                         } else {
8633                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
8634                                 ins->type = STACK_R8;
8635                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8636                                 ins->inst_p0 = d;
8637                                 MONO_ADD_INS (bblock, ins);
8638                         }
8639                         ++ip;
8640                         readr8 (ip, d);
8641                         ip += 8;
8642                         *sp++ = ins;
8643                         break;
8644                 }
8645                 case CEE_DUP: {
8646                         MonoInst *temp, *store;
8647                         CHECK_STACK (1);
8648                         CHECK_STACK_OVF (1);
8649                         sp--;
8650                         ins = *sp;
8651
8652                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
8653                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
8654
8655                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8656                         *sp++ = ins;
8657
8658                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8659                         *sp++ = ins;
8660
8661                         ++ip;
8662                         inline_costs += 2;
8663                         break;
8664                 }
8665                 case CEE_POP:
8666                         CHECK_STACK (1);
8667                         ip++;
8668                         --sp;
8669
8670 #ifdef TARGET_X86
8671                         if (sp [0]->type == STACK_R8)
8672                                 /* we need to pop the value from the x86 FP stack */
8673                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
8674 #endif
8675                         break;
8676                 case CEE_JMP: {
8677                         MonoCallInst *call;
8678
8679                         INLINE_FAILURE ("jmp");
8680                         GSHAREDVT_FAILURE (*ip);
8681
8682                         CHECK_OPSIZE (5);
8683                         if (stack_start != sp)
8684                                 UNVERIFIED;
8685                         token = read32 (ip + 1);
8686                         /* FIXME: check the signature matches */
8687                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8688
8689                         if (!cmethod || mono_loader_get_last_error ())
8690                                 LOAD_ERROR;
8691  
8692                         if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod))
8693                                 GENERIC_SHARING_FAILURE (CEE_JMP);
8694
8695                         if (mono_security_cas_enabled ())
8696                                 CHECK_CFG_EXCEPTION;
8697
8698                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
8699
8700                         if (ARCH_HAVE_OP_TAIL_CALL) {
8701                                 MonoMethodSignature *fsig = mono_method_signature (cmethod);
8702                                 int i, n;
8703
8704                                 /* Handle tail calls similarly to calls */
8705                                 n = fsig->param_count + fsig->hasthis;
8706
8707                                 DISABLE_AOT (cfg);
8708
8709                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
8710                                 call->method = cmethod;
8711                                 call->tail_call = TRUE;
8712                                 call->signature = mono_method_signature (cmethod);
8713                                 call->args = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
8714                                 call->inst.inst_p0 = cmethod;
8715                                 for (i = 0; i < n; ++i)
8716                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
8717
8718                                 mono_arch_emit_call (cfg, call);
8719                                 cfg->param_area = MAX(cfg->param_area, call->stack_usage);
8720                                 MONO_ADD_INS (bblock, (MonoInst*)call);
8721                         } else {
8722                                 for (i = 0; i < num_args; ++i)
8723                                         /* Prevent arguments from being optimized away */
8724                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
8725
8726                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
8727                                 ins = (MonoInst*)call;
8728                                 ins->inst_p0 = cmethod;
8729                                 MONO_ADD_INS (bblock, ins);
8730                         }
8731
8732                         ip += 5;
8733                         start_new_bblock = 1;
8734                         break;
8735                 }
8736                 case CEE_CALLI: {
8737                         MonoInst *addr;
8738                         MonoMethodSignature *fsig;
8739
8740                         CHECK_OPSIZE (5);
8741                         token = read32 (ip + 1);
8742
8743                         ins = NULL;
8744
8745                         //GSHAREDVT_FAILURE (*ip);
8746                         cmethod = NULL;
8747                         CHECK_STACK (1);
8748                         --sp;
8749                         addr = *sp;
8750                         fsig = mini_get_signature (method, token, generic_context);
8751
8752                         if (method->dynamic && fsig->pinvoke) {
8753                                 MonoInst *args [3];
8754
8755                                 /*
8756                                  * This is a call through a function pointer using a pinvoke
8757                                  * signature. Have to create a wrapper and call that instead.
8758                                  * FIXME: This is very slow, need to create a wrapper at JIT time
8759                                  * instead based on the signature.
8760                                  */
8761                                 EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
8762                                 EMIT_NEW_PCONST (cfg, args [1], fsig);
8763                                 args [2] = addr;
8764                                 addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
8765                         }
8766
8767                         n = fsig->param_count + fsig->hasthis;
8768
8769                         CHECK_STACK (n);
8770
8771                         //g_assert (!virtual || fsig->hasthis);
8772
8773                         sp -= n;
8774
8775                         inline_costs += 10 * num_calls++;
8776
8777                         /*
8778                          * Making generic calls out of gsharedvt methods.
8779                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
8780                          * patching gshared method addresses into a gsharedvt method.
8781                          */
8782                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig)) {
8783                                 /*
8784                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
8785                                  */
8786                                 MonoInst *callee = addr;
8787
8788                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
8789                                         /* Not tested */
8790                                         GSHAREDVT_FAILURE (*ip);
8791
8792                                 addr = emit_get_rgctx_sig (cfg, context_used,
8793                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
8794                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
8795                                 goto calli_end;
8796                         }
8797
8798                         /* Prevent inlining of methods with indirect calls */
8799                         INLINE_FAILURE ("indirect call");
8800
8801                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
8802                                 int info_type;
8803                                 gpointer info_data;
8804
8805                                 /*
8806                                  * Instead of emitting an indirect call, emit a direct call
8807                                  * with the contents of the aotconst as the patch info.
8808                                  */
8809                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
8810                                         info_type = addr->inst_c1;
8811                                         info_data = addr->inst_p0;
8812                                 } else {
8813                                         info_type = addr->inst_right->inst_c1;
8814                                         info_data = addr->inst_right->inst_left;
8815                                 }
8816
8817                                 if (info_type == MONO_PATCH_INFO_ICALL_ADDR || info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
8818                                         ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
8819                                         NULLIFY_INS (addr);
8820                                         goto calli_end;
8821                                 }
8822                         }
8823                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8824
8825                         calli_end:
8826
8827                         /* End of call, INS should contain the result of the call, if any */
8828
8829                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8830                                 g_assert (ins);
8831                                 *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
8832                         }
8833
8834                         CHECK_CFG_EXCEPTION;
8835
8836                         ip += 5;
8837                         ins_flag = 0;
8838                         constrained_class = NULL;
8839                         break;
8840                 }
8841                 case CEE_CALL:
8842                 case CEE_CALLVIRT: {
8843                         MonoInst *addr = NULL;
8844                         MonoMethodSignature *fsig = NULL;
8845                         int array_rank = 0;
8846                         int virtual = *ip == CEE_CALLVIRT;
8847                         gboolean pass_imt_from_rgctx = FALSE;
8848                         MonoInst *imt_arg = NULL;
8849                         MonoInst *keep_this_alive = NULL;
8850                         gboolean pass_vtable = FALSE;
8851                         gboolean pass_mrgctx = FALSE;
8852                         MonoInst *vtable_arg = NULL;
8853                         gboolean check_this = FALSE;
8854                         gboolean supported_tail_call = FALSE;
8855                         gboolean tail_call = FALSE;
8856                         gboolean need_seq_point = FALSE;
8857                         guint32 call_opcode = *ip;
8858                         gboolean emit_widen = TRUE;
8859                         gboolean push_res = TRUE;
8860                         gboolean skip_ret = FALSE;
8861                         gboolean delegate_invoke = FALSE;
8862                         gboolean direct_icall = FALSE;
8863                         gboolean constrained_partial_call = FALSE;
8864                         MonoMethod *cil_method;
8865
8866                         CHECK_OPSIZE (5);
8867                         token = read32 (ip + 1);
8868
8869                         ins = NULL;
8870
8871                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8872                         cil_method = cmethod;
8873                                 
8874                         if (constrained_class) {
8875                                 if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->generic_sharing_context) {
8876                                         if (!mini_is_gsharedvt_klass (cfg, constrained_class)) {
8877                                                 g_assert (!cmethod->klass->valuetype);
8878                                                 if (!mini_type_is_reference (cfg, &constrained_class->byval_arg))
8879                                                         constrained_partial_call = TRUE;
8880                                         }
8881                                 }
8882
8883                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
8884                                         if (cfg->verbose_level > 2)
8885                                                 printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_class));
8886                                         if (!((constrained_class->byval_arg.type == MONO_TYPE_VAR ||
8887                                                    constrained_class->byval_arg.type == MONO_TYPE_MVAR) &&
8888                                                   cfg->generic_sharing_context)) {
8889                                                 cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_class, generic_context, &cfg->error);
8890                                                 CHECK_CFG_ERROR;
8891                                         }
8892                                 } else {
8893                                         if (cfg->verbose_level > 2)
8894                                                 printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_class));
8895
8896                                         if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->generic_sharing_context) {
8897                                                 /* 
8898                                                  * This is needed since get_method_constrained can't find 
8899                                                  * the method in klass representing a type var.
8900                                                  * The type var is guaranteed to be a reference type in this
8901                                                  * case.
8902                                                  */
8903                                                 if (!mini_is_gsharedvt_klass (cfg, constrained_class))
8904                                                         g_assert (!cmethod->klass->valuetype);
8905                                         } else {
8906                                                 cmethod = mono_get_method_constrained_checked (image, token, constrained_class, generic_context, &cil_method, &cfg->error);
8907                                                 CHECK_CFG_ERROR;
8908                                         }
8909                                 }
8910                         }
8911                                         
8912                         if (!cmethod || mono_loader_get_last_error ())
8913                                 LOAD_ERROR;
8914                         if (!dont_verify && !cfg->skip_visibility) {
8915                                 MonoMethod *target_method = cil_method;
8916                                 if (method->is_inflated) {
8917                                         target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context));
8918                                 }
8919                                 if (!mono_method_can_access_method (method_definition, target_method) &&
8920                                         !mono_method_can_access_method (method, cil_method))
8921                                         METHOD_ACCESS_FAILURE (method, cil_method);
8922                         }
8923
8924                         if (mono_security_core_clr_enabled ())
8925                                 ensure_method_is_allowed_to_call_method (cfg, method, cil_method, bblock, ip);
8926
8927                         if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
8928                                 /* MS.NET seems to silently convert this to a callvirt */
8929                                 virtual = 1;
8930
8931                         {
8932                                 /*
8933                                  * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
8934                                  * converts to a callvirt.
8935                                  *
8936                                  * tests/bug-515884.il is an example of this behavior
8937                                  */
8938                                 const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
8939                                 const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
8940                                 if (!virtual && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
8941                                         virtual = 1;
8942                         }
8943
8944                         if (!cmethod->klass->inited)
8945                                 if (!mono_class_init (cmethod->klass))
8946                                         TYPE_LOAD_ERROR (cmethod->klass);
8947
8948                         fsig = mono_method_signature (cmethod);
8949                         if (!fsig)
8950                                 LOAD_ERROR;
8951                         if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
8952                                 mini_class_is_system_array (cmethod->klass)) {
8953                                 array_rank = cmethod->klass->rank;
8954                         } else if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && icall_is_direct_callable (cfg, cmethod)) {
8955                                 direct_icall = TRUE;
8956                         } else if (fsig->pinvoke) {
8957                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod,
8958                                                                                                                                            check_for_pending_exc, cfg->compile_aot);
8959                                 fsig = mono_method_signature (wrapper);
8960                         } else if (constrained_class) {
8961                         } else {
8962                                 fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
8963                                 CHECK_CFG_ERROR;
8964                         }
8965
8966                         mono_save_token_info (cfg, image, token, cil_method);
8967
8968                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip + 5 - header->code)))
8969                                 need_seq_point = TRUE;
8970
8971                         /* Don't support calls made using type arguments for now */
8972                         /*
8973                           if (cfg->gsharedvt) {
8974                           if (mini_is_gsharedvt_signature (cfg, fsig))
8975                           GSHAREDVT_FAILURE (*ip);
8976                           }
8977                         */
8978
8979                         if (mono_security_cas_enabled ()) {
8980                                 if (check_linkdemand (cfg, method, cmethod))
8981                                         INLINE_FAILURE ("linkdemand");
8982                                 CHECK_CFG_EXCEPTION;
8983                         }
8984
8985                         if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
8986                                 g_assert_not_reached ();
8987
8988                         n = fsig->param_count + fsig->hasthis;
8989
8990                         if (!cfg->generic_sharing_context && cmethod->klass->generic_container)
8991                                 UNVERIFIED;
8992
8993                         if (!cfg->generic_sharing_context)
8994                                 g_assert (!mono_method_check_context_used (cmethod));
8995
8996                         CHECK_STACK (n);
8997
8998                         //g_assert (!virtual || fsig->hasthis);
8999
9000                         sp -= n;
9001
9002                         if (constrained_class) {
9003                                 if (mini_is_gsharedvt_klass (cfg, constrained_class)) {
9004                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_class->valuetype && cmethod->klass->valuetype) {
9005                                                 /* The 'Own method' case below */
9006                                         } else if (cmethod->klass->image != mono_defaults.corlib && !(cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !cmethod->klass->valuetype) {
9007                                                 /* 'The type parameter is instantiated as a reference type' case below. */
9008                                         } else {
9009                                                 ins = handle_constrained_gsharedvt_call (cfg, cmethod, fsig, sp, constrained_class, &emit_widen, &bblock);
9010                                                 CHECK_CFG_EXCEPTION;
9011                                                 g_assert (ins);
9012                                                 goto call_end;
9013                                         }
9014                                 }
9015
9016                                 /*
9017                                  * We have the `constrained.' prefix opcode.
9018                                  */
9019                                 if (constrained_partial_call) {
9020                                         gboolean need_box = TRUE;
9021
9022                                         /*
9023                                          * The receiver is a valuetype, but the exact type is not known at compile time. This means the
9024                                          * called method is not known at compile time either. The called method could end up being
9025                                          * one of the methods on the parent classes (object/valuetype/enum), in which case we need
9026                                          * to box the receiver.
9027                                          * A simple solution would be to box always and make a normal virtual call, but that would
9028                                          * be bad performance wise.
9029                                          */
9030                                         if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE && cmethod->klass->generic_class) {
9031                                                 /*
9032                                                  * The parent classes implement no generic interfaces, so the called method will be a vtype method, so no boxing neccessary.
9033                                                  */
9034                                                 need_box = FALSE;
9035                                         }
9036
9037                                         if (need_box) {
9038                                                 MonoInst *box_type;
9039                                                 MonoBasicBlock *is_ref_bb, *end_bb;
9040                                                 MonoInst *nonbox_call;
9041
9042                                                 /*
9043                                                  * Determine at runtime whenever the called method is defined on object/valuetype/enum, and emit a boxing call
9044                                                  * if needed.
9045                                                  * FIXME: It is possible to inline the called method in a lot of cases, i.e. for T_INT,
9046                                                  * the no-box case goes to a method in Int32, while the box case goes to a method in Enum.
9047                                                  */
9048                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
9049
9050                                                 NEW_BBLOCK (cfg, is_ref_bb);
9051                                                 NEW_BBLOCK (cfg, end_bb);
9052
9053                                                 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);
9054                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, box_type->dreg, 1);
9055                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
9056
9057                                                 /* Non-ref case */
9058                                                 nonbox_call = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9059
9060                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9061
9062                                                 /* Ref case */
9063                                                 MONO_START_BB (cfg, is_ref_bb);
9064                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9065                                                 ins->klass = constrained_class;
9066                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class), &bblock);
9067                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9068
9069                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9070
9071                                                 MONO_START_BB (cfg, end_bb);
9072                                                 bblock = end_bb;
9073
9074                                                 nonbox_call->dreg = ins->dreg;
9075                                         } else {
9076                                                 g_assert (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
9077                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
9078                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9079                                         }
9080                                         goto call_end;
9081                                 } else if (constrained_class->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
9082                                         /*
9083                                          * The type parameter is instantiated as a valuetype,
9084                                          * but that type doesn't override the method we're
9085                                          * calling, so we need to box `this'.
9086                                          */
9087                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9088                                         ins->klass = constrained_class;
9089                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class), &bblock);
9090                                         CHECK_CFG_EXCEPTION;
9091                                 } else if (!constrained_class->valuetype) {
9092                                         int dreg = alloc_ireg_ref (cfg);
9093
9094                                         /*
9095                                          * The type parameter is instantiated as a reference
9096                                          * type.  We have a managed pointer on the stack, so
9097                                          * we need to dereference it here.
9098                                          */
9099                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
9100                                         ins->type = STACK_OBJ;
9101                                         sp [0] = ins;
9102                                 } else {
9103                                         if (cmethod->klass->valuetype) {
9104                                                 /* Own method */
9105                                         } else {
9106                                                 /* Interface method */
9107                                                 int ioffset, slot;
9108
9109                                                 mono_class_setup_vtable (constrained_class);
9110                                                 CHECK_TYPELOAD (constrained_class);
9111                                                 ioffset = mono_class_interface_offset (constrained_class, cmethod->klass);
9112                                                 if (ioffset == -1)
9113                                                         TYPE_LOAD_ERROR (constrained_class);
9114                                                 slot = mono_method_get_vtable_slot (cmethod);
9115                                                 if (slot == -1)
9116                                                         TYPE_LOAD_ERROR (cmethod->klass);
9117                                                 cmethod = constrained_class->vtable [ioffset + slot];
9118
9119                                                 if (cmethod->klass == mono_defaults.enum_class) {
9120                                                         /* Enum implements some interfaces, so treat this as the first case */
9121                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9122                                                         ins->klass = constrained_class;
9123                                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class), &bblock);
9124                                                         CHECK_CFG_EXCEPTION;
9125                                                 }
9126                                         }
9127                                         virtual = 0;
9128                                 }
9129                                 constrained_class = NULL;
9130                         }
9131
9132                         if (check_call_signature (cfg, fsig, sp))
9133                                 UNVERIFIED;
9134
9135 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
9136                         if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
9137                                 delegate_invoke = TRUE;
9138 #endif
9139
9140                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
9141                                 bblock = cfg->cbb;
9142                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9143                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9144                                         emit_widen = FALSE;
9145                                 }
9146
9147                                 goto call_end;
9148                         }
9149
9150                         /* 
9151                          * If the callee is a shared method, then its static cctor
9152                          * might not get called after the call was patched.
9153                          */
9154                         if (cfg->generic_sharing_context && cmethod->klass != method->klass && cmethod->klass->generic_class && mono_method_is_generic_sharable (cmethod, TRUE) && mono_class_needs_cctor_run (cmethod->klass, method)) {
9155                                 emit_generic_class_init (cfg, cmethod->klass);
9156                                 CHECK_TYPELOAD (cmethod->klass);
9157                         }
9158
9159                         check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
9160
9161                         if (cfg->generic_sharing_context) {
9162                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
9163
9164                                 context_used = mini_method_check_context_used (cfg, cmethod);
9165
9166                                 if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9167                                         /* Generic method interface
9168                                            calls are resolved via a
9169                                            helper function and don't
9170                                            need an imt. */
9171                                         if (!cmethod_context || !cmethod_context->method_inst)
9172                                                 pass_imt_from_rgctx = TRUE;
9173                                 }
9174
9175                                 /*
9176                                  * If a shared method calls another
9177                                  * shared method then the caller must
9178                                  * have a generic sharing context
9179                                  * because the magic trampoline
9180                                  * requires it.  FIXME: We shouldn't
9181                                  * have to force the vtable/mrgctx
9182                                  * variable here.  Instead there
9183                                  * should be a flag in the cfg to
9184                                  * request a generic sharing context.
9185                                  */
9186                                 if (context_used &&
9187                                                 ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
9188                                         mono_get_vtable_var (cfg);
9189                         }
9190
9191                         if (pass_vtable) {
9192                                 if (context_used) {
9193                                         vtable_arg = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
9194                                 } else {
9195                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
9196
9197                                         CHECK_TYPELOAD (cmethod->klass);
9198                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
9199                                 }
9200                         }
9201
9202                         if (pass_mrgctx) {
9203                                 g_assert (!vtable_arg);
9204
9205                                 if (!cfg->compile_aot) {
9206                                         /* 
9207                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
9208                                          * for type load errors before.
9209                                          */
9210                                         mono_class_setup_vtable (cmethod->klass);
9211                                         CHECK_TYPELOAD (cmethod->klass);
9212                                 }
9213
9214                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
9215
9216                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
9217                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
9218                                          MONO_METHOD_IS_FINAL (cmethod)) &&
9219                                         !mono_class_is_marshalbyref (cmethod->klass)) {
9220                                         if (virtual)
9221                                                 check_this = TRUE;
9222                                         virtual = 0;
9223                                 }
9224                         }
9225
9226                         if (pass_imt_from_rgctx) {
9227                                 g_assert (!pass_vtable);
9228
9229                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9230                                         cmethod, MONO_RGCTX_INFO_METHOD);
9231                         }
9232
9233                         if (check_this)
9234                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9235
9236                         /* Calling virtual generic methods */
9237                         if (virtual && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && 
9238                             !(MONO_METHOD_IS_FINAL (cmethod) && 
9239                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
9240                             fsig->generic_param_count && 
9241                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))) {
9242                                 MonoInst *this_temp, *this_arg_temp, *store;
9243                                 MonoInst *iargs [4];
9244                                 gboolean use_imt = FALSE;
9245
9246                                 g_assert (fsig->is_inflated);
9247
9248                                 /* Prevent inlining of methods that contain indirect calls */
9249                                 INLINE_FAILURE ("virtual generic call");
9250
9251                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))
9252                                         GSHAREDVT_FAILURE (*ip);
9253
9254 #if MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK && defined(MONO_ARCH_GSHARED_SUPPORTED)
9255                                 if (cmethod->wrapper_type == MONO_WRAPPER_NONE)
9256                                         use_imt = TRUE;
9257 #endif
9258
9259                                 if (use_imt) {
9260                                         g_assert (!imt_arg);
9261                                         if (!context_used)
9262                                                 g_assert (cmethod->is_inflated);
9263                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
9264                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
9265                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
9266                                 } else {
9267                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
9268                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
9269                                         MONO_ADD_INS (bblock, store);
9270
9271                                         /* FIXME: This should be a managed pointer */
9272                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
9273
9274                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
9275                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
9276                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
9277                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
9278                                         addr = mono_emit_jit_icall (cfg,
9279                                                                                                 mono_helper_compile_generic_method, iargs);
9280
9281                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
9282
9283                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9284                                 }
9285
9286                                 goto call_end;
9287                         }
9288
9289                         /*
9290                          * Implement a workaround for the inherent races involved in locking:
9291                          * Monitor.Enter ()
9292                          * try {
9293                          * } finally {
9294                          *    Monitor.Exit ()
9295                          * }
9296                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
9297                          * try block, the Exit () won't be executed, see:
9298                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
9299                          * To work around this, we extend such try blocks to include the last x bytes
9300                          * of the Monitor.Enter () call.
9301                          */
9302                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
9303                                 MonoBasicBlock *tbb;
9304
9305                                 GET_BBLOCK (cfg, tbb, ip + 5);
9306                                 /* 
9307                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
9308                                  * from Monitor.Enter like ArgumentNullException.
9309                                  */
9310                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9311                                         /* Mark this bblock as needing to be extended */
9312                                         tbb->extend_try_block = TRUE;
9313                                 }
9314                         }
9315
9316                         /* Conversion to a JIT intrinsic */
9317                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
9318                                 bblock = cfg->cbb;
9319                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9320                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9321                                         emit_widen = FALSE;
9322                                 }
9323                                 goto call_end;
9324                         }
9325
9326                         /* Inlining */
9327                         if ((cfg->opt & MONO_OPT_INLINE) &&
9328                                 (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
9329                             mono_method_check_inlining (cfg, cmethod)) {
9330                                 int costs;
9331                                 gboolean always = FALSE;
9332
9333                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
9334                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
9335                                         /* Prevent inlining of methods that call wrappers */
9336                                         INLINE_FAILURE ("wrapper call");
9337                                         cmethod = mono_marshal_get_native_wrapper (cmethod, check_for_pending_exc, FALSE);
9338                                         always = TRUE;
9339                                 }
9340
9341                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, always, &bblock);
9342                                 if (costs) {
9343                                         cfg->real_offset += 5;
9344
9345                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9346                                                 /* *sp is already set by inline_method */
9347                                                 sp++;
9348                                                 push_res = FALSE;
9349                                         }
9350
9351                                         inline_costs += costs;
9352
9353                                         goto call_end;
9354                                 }
9355                         }
9356
9357                         /* Tail recursion elimination */
9358                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
9359                                 gboolean has_vtargs = FALSE;
9360                                 int i;
9361
9362                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9363                                 INLINE_FAILURE ("tail call");
9364
9365                                 /* keep it simple */
9366                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
9367                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
9368                                                 has_vtargs = TRUE;
9369                                 }
9370
9371                                 if (!has_vtargs) {
9372                                         for (i = 0; i < n; ++i)
9373                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9374                                         MONO_INST_NEW (cfg, ins, OP_BR);
9375                                         MONO_ADD_INS (bblock, ins);
9376                                         tblock = start_bblock->out_bb [0];
9377                                         link_bblock (cfg, bblock, tblock);
9378                                         ins->inst_target_bb = tblock;
9379                                         start_new_bblock = 1;
9380
9381                                         /* skip the CEE_RET, too */
9382                                         if (ip_in_bb (cfg, bblock, ip + 5))
9383                                                 skip_ret = TRUE;
9384                                         push_res = FALSE;
9385                                         goto call_end;
9386                                 }
9387                         }
9388
9389                         inline_costs += 10 * num_calls++;
9390
9391                         /*
9392                          * Making generic calls out of gsharedvt methods.
9393                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9394                          * patching gshared method addresses into a gsharedvt method.
9395                          */
9396                         if (cfg->gsharedvt && (mini_is_gsharedvt_signature (cfg, fsig) || cmethod->is_inflated || cmethod->klass->generic_class) &&
9397                                 !(cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY)) {
9398                                 MonoRgctxInfoType info_type;
9399
9400                                 if (virtual) {
9401                                         //if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
9402                                                 //GSHAREDVT_FAILURE (*ip);
9403                                         // disable for possible remoting calls
9404                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
9405                                                 GSHAREDVT_FAILURE (*ip);
9406                                         if (fsig->generic_param_count) {
9407                                                 /* virtual generic call */
9408                                                 g_assert (!imt_arg);
9409                                                 /* Same as the virtual generic case above */
9410                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9411                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9412                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
9413                                                 vtable_arg = NULL;
9414                                         } else if ((cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !imt_arg) {
9415                                                 /* This can happen when we call a fully instantiated iface method */
9416                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9417                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9418                                                 vtable_arg = NULL;
9419                                         }
9420                                 }
9421
9422                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
9423                                         keep_this_alive = sp [0];
9424
9425                                 if (virtual && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
9426                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
9427                                 else
9428                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
9429                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
9430
9431                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9432                                 goto call_end;
9433                         }
9434
9435                         /* Generic sharing */
9436
9437                         /*
9438                          * Use this if the callee is gsharedvt sharable too, since
9439                          * at runtime we might find an instantiation so the call cannot
9440                          * be patched (the 'no_patch' code path in mini-trampolines.c).
9441                          */
9442                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
9443                                 (!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
9444                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
9445                                 (!virtual || MONO_METHOD_IS_FINAL (cmethod) ||
9446                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
9447                                 INLINE_FAILURE ("gshared");
9448
9449                                 g_assert (cfg->generic_sharing_context && cmethod);
9450                                 g_assert (!addr);
9451
9452                                 /*
9453                                  * We are compiling a call to a
9454                                  * generic method from shared code,
9455                                  * which means that we have to look up
9456                                  * the method in the rgctx and do an
9457                                  * indirect call.
9458                                  */
9459                                 if (fsig->hasthis)
9460                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9461
9462                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9463                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9464                                 goto call_end;
9465                         }
9466
9467                         /* Direct calls to icalls */
9468                         if (direct_icall) {
9469                                 MonoMethod *wrapper;
9470                                 int costs;
9471
9472                                 /* Inline the wrapper */
9473                                 wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9474
9475                                 costs = inline_method (cfg, wrapper, fsig, sp, ip, cfg->real_offset, TRUE, &bblock);
9476                                 g_assert (costs > 0);
9477                                 cfg->real_offset += 5;
9478
9479                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9480                                         /* *sp is already set by inline_method */
9481                                         sp++;
9482                                         push_res = FALSE;
9483                                 }
9484
9485                                 inline_costs += costs;
9486
9487                                 goto call_end;
9488                         }
9489                                         
9490                         /* Array methods */
9491                         if (array_rank) {
9492                                 MonoInst *addr;
9493
9494                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
9495                                         MonoInst *val = sp [fsig->param_count];
9496
9497                                         if (val->type == STACK_OBJ) {
9498                                                 MonoInst *iargs [2];
9499
9500                                                 iargs [0] = sp [0];
9501                                                 iargs [1] = val;
9502                                                 
9503                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
9504                                         }
9505                                         
9506                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
9507                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
9508                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !(val->opcode == OP_PCONST && val->inst_c0 == 0))
9509                                                 emit_write_barrier (cfg, addr, val);
9510                                         if (cfg->gen_write_barriers && mini_is_gsharedvt_klass (cfg, cmethod->klass))
9511                                                 GSHAREDVT_FAILURE (*ip);
9512                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
9513                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9514
9515                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
9516                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
9517                                         if (!cmethod->klass->element_class->valuetype && !readonly)
9518                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
9519                                         CHECK_TYPELOAD (cmethod->klass);
9520                                         
9521                                         readonly = FALSE;
9522                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9523                                         ins = addr;
9524                                 } else {
9525                                         g_assert_not_reached ();
9526                                 }
9527
9528                                 emit_widen = FALSE;
9529                                 goto call_end;
9530                         }
9531
9532                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL);
9533                         if (ins)
9534                                 goto call_end;
9535
9536                         /* Tail prefix / tail call optimization */
9537
9538                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
9539                         /* FIXME: runtime generic context pointer for jumps? */
9540                         /* FIXME: handle this for generic sharing eventually */
9541                         if ((ins_flag & MONO_INST_TAILCALL) &&
9542                                 !vtable_arg && !cfg->generic_sharing_context && is_supported_tail_call (cfg, method, cmethod, fsig, call_opcode))
9543                                 supported_tail_call = TRUE;
9544
9545                         if (supported_tail_call) {
9546                                 MonoCallInst *call;
9547
9548                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9549                                 INLINE_FAILURE ("tail call");
9550
9551                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
9552
9553                                 if (ARCH_HAVE_OP_TAIL_CALL) {
9554                                         /* Handle tail calls similarly to normal calls */
9555                                         tail_call = TRUE;
9556                                 } else {
9557                                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9558
9559                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9560                                         call->tail_call = TRUE;
9561                                         call->method = cmethod;
9562                                         call->signature = mono_method_signature (cmethod);
9563
9564                                         /*
9565                                          * We implement tail calls by storing the actual arguments into the 
9566                                          * argument variables, then emitting a CEE_JMP.
9567                                          */
9568                                         for (i = 0; i < n; ++i) {
9569                                                 /* Prevent argument from being register allocated */
9570                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
9571                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9572                                         }
9573                                         ins = (MonoInst*)call;
9574                                         ins->inst_p0 = cmethod;
9575                                         ins->inst_p1 = arg_array [0];
9576                                         MONO_ADD_INS (bblock, ins);
9577                                         link_bblock (cfg, bblock, end_bblock);                  
9578                                         start_new_bblock = 1;
9579
9580                                         // FIXME: Eliminate unreachable epilogs
9581
9582                                         /*
9583                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9584                                          * only reachable from this call.
9585                                          */
9586                                         GET_BBLOCK (cfg, tblock, ip + 5);
9587                                         if (tblock == bblock || tblock->in_count == 0)
9588                                                 skip_ret = TRUE;
9589                                         push_res = FALSE;
9590
9591                                         goto call_end;
9592                                 }
9593                         }
9594
9595                         /* 
9596                          * Synchronized wrappers.
9597                          * Its hard to determine where to replace a method with its synchronized
9598                          * wrapper without causing an infinite recursion. The current solution is
9599                          * to add the synchronized wrapper in the trampolines, and to
9600                          * change the called method to a dummy wrapper, and resolve that wrapper
9601                          * to the real method in mono_jit_compile_method ().
9602                          */
9603                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
9604                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
9605                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
9606                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
9607                         }
9608
9609                         /* Common call */
9610                         INLINE_FAILURE ("call");
9611                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual ? sp [0] : NULL,
9612                                                                                           imt_arg, vtable_arg);
9613
9614                         if (tail_call) {
9615                                 link_bblock (cfg, bblock, end_bblock);                  
9616                                 start_new_bblock = 1;
9617
9618                                 // FIXME: Eliminate unreachable epilogs
9619
9620                                 /*
9621                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9622                                  * only reachable from this call.
9623                                  */
9624                                 GET_BBLOCK (cfg, tblock, ip + 5);
9625                                 if (tblock == bblock || tblock->in_count == 0)
9626                                         skip_ret = TRUE;
9627                                 push_res = FALSE;
9628                         }
9629
9630                         call_end:
9631
9632                         /* End of call, INS should contain the result of the call, if any */
9633
9634                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
9635                                 g_assert (ins);
9636                                 if (emit_widen)
9637                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
9638                                 else
9639                                         *sp++ = ins;
9640                         }
9641
9642                         if (keep_this_alive) {
9643                                 MonoInst *dummy_use;
9644
9645                                 /* See mono_emit_method_call_full () */
9646                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
9647                         }
9648
9649                         CHECK_CFG_EXCEPTION;
9650
9651                         ip += 5;
9652                         if (skip_ret) {
9653                                 g_assert (*ip == CEE_RET);
9654                                 ip += 1;
9655                         }
9656                         ins_flag = 0;
9657                         constrained_class = NULL;
9658                         if (need_seq_point)
9659                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
9660                         break;
9661                 }
9662                 case CEE_RET:
9663                         if (cfg->method != method) {
9664                                 /* return from inlined method */
9665                                 /* 
9666                                  * If in_count == 0, that means the ret is unreachable due to
9667                                  * being preceeded by a throw. In that case, inline_method () will
9668                                  * handle setting the return value 
9669                                  * (test case: test_0_inline_throw ()).
9670                                  */
9671                                 if (return_var && cfg->cbb->in_count) {
9672                                         MonoType *ret_type = mono_method_signature (method)->ret;
9673
9674                                         MonoInst *store;
9675                                         CHECK_STACK (1);
9676                                         --sp;
9677
9678                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9679                                                 UNVERIFIED;
9680
9681                                         //g_assert (returnvar != -1);
9682                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
9683                                         cfg->ret_var_set = TRUE;
9684                                 } 
9685                         } else {
9686                                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
9687
9688                                 if (cfg->lmf_var && cfg->cbb->in_count)
9689                                         emit_pop_lmf (cfg);
9690
9691                                 if (cfg->ret) {
9692                                         MonoType *ret_type = mini_get_underlying_type (cfg, mono_method_signature (method)->ret);
9693
9694                                         if (seq_points && !sym_seq_points) {
9695                                                 /* 
9696                                                  * Place a seq point here too even through the IL stack is not
9697                                                  * empty, so a step over on
9698                                                  * call <FOO>
9699                                                  * ret
9700                                                  * will work correctly.
9701                                                  */
9702                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
9703                                                 MONO_ADD_INS (cfg->cbb, ins);
9704                                         }
9705
9706                                         g_assert (!return_var);
9707                                         CHECK_STACK (1);
9708                                         --sp;
9709
9710                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9711                                                 UNVERIFIED;
9712
9713                                         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
9714                                                 MonoInst *ret_addr;
9715
9716                                                 if (!cfg->vret_addr) {
9717                                                         MonoInst *ins;
9718
9719                                                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, (*sp));
9720                                                 } else {
9721                                                         EMIT_NEW_RETLOADA (cfg, ret_addr);
9722
9723                                                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, (*sp)->dreg);
9724                                                         ins->klass = mono_class_from_mono_type (ret_type);
9725                                                 }
9726                                         } else {
9727 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
9728                                                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
9729                                                         MonoInst *iargs [1];
9730                                                         MonoInst *conv;
9731
9732                                                         iargs [0] = *sp;
9733                                                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
9734                                                         mono_arch_emit_setret (cfg, method, conv);
9735                                                 } else {
9736                                                         mono_arch_emit_setret (cfg, method, *sp);
9737                                                 }
9738 #else
9739                                                 mono_arch_emit_setret (cfg, method, *sp);
9740 #endif
9741                                         }
9742                                 }
9743                         }
9744                         if (sp != stack_start)
9745                                 UNVERIFIED;
9746                         MONO_INST_NEW (cfg, ins, OP_BR);
9747                         ip++;
9748                         ins->inst_target_bb = end_bblock;
9749                         MONO_ADD_INS (bblock, ins);
9750                         link_bblock (cfg, bblock, end_bblock);
9751                         start_new_bblock = 1;
9752                         break;
9753                 case CEE_BR_S:
9754                         CHECK_OPSIZE (2);
9755                         MONO_INST_NEW (cfg, ins, OP_BR);
9756                         ip++;
9757                         target = ip + 1 + (signed char)(*ip);
9758                         ++ip;
9759                         GET_BBLOCK (cfg, tblock, target);
9760                         link_bblock (cfg, bblock, tblock);
9761                         ins->inst_target_bb = tblock;
9762                         if (sp != stack_start) {
9763                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9764                                 sp = stack_start;
9765                                 CHECK_UNVERIFIABLE (cfg);
9766                         }
9767                         MONO_ADD_INS (bblock, ins);
9768                         start_new_bblock = 1;
9769                         inline_costs += BRANCH_COST;
9770                         break;
9771                 case CEE_BEQ_S:
9772                 case CEE_BGE_S:
9773                 case CEE_BGT_S:
9774                 case CEE_BLE_S:
9775                 case CEE_BLT_S:
9776                 case CEE_BNE_UN_S:
9777                 case CEE_BGE_UN_S:
9778                 case CEE_BGT_UN_S:
9779                 case CEE_BLE_UN_S:
9780                 case CEE_BLT_UN_S:
9781                         CHECK_OPSIZE (2);
9782                         CHECK_STACK (2);
9783                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
9784                         ip++;
9785                         target = ip + 1 + *(signed char*)ip;
9786                         ip++;
9787
9788                         ADD_BINCOND (NULL);
9789
9790                         sp = stack_start;
9791                         inline_costs += BRANCH_COST;
9792                         break;
9793                 case CEE_BR:
9794                         CHECK_OPSIZE (5);
9795                         MONO_INST_NEW (cfg, ins, OP_BR);
9796                         ip++;
9797
9798                         target = ip + 4 + (gint32)read32(ip);
9799                         ip += 4;
9800                         GET_BBLOCK (cfg, tblock, target);
9801                         link_bblock (cfg, bblock, tblock);
9802                         ins->inst_target_bb = tblock;
9803                         if (sp != stack_start) {
9804                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9805                                 sp = stack_start;
9806                                 CHECK_UNVERIFIABLE (cfg);
9807                         }
9808
9809                         MONO_ADD_INS (bblock, ins);
9810
9811                         start_new_bblock = 1;
9812                         inline_costs += BRANCH_COST;
9813                         break;
9814                 case CEE_BRFALSE_S:
9815                 case CEE_BRTRUE_S:
9816                 case CEE_BRFALSE:
9817                 case CEE_BRTRUE: {
9818                         MonoInst *cmp;
9819                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
9820                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
9821                         guint32 opsize = is_short ? 1 : 4;
9822
9823                         CHECK_OPSIZE (opsize);
9824                         CHECK_STACK (1);
9825                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
9826                                 UNVERIFIED;
9827                         ip ++;
9828                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
9829                         ip += opsize;
9830
9831                         sp--;
9832
9833                         GET_BBLOCK (cfg, tblock, target);
9834                         link_bblock (cfg, bblock, tblock);
9835                         GET_BBLOCK (cfg, tblock, ip);
9836                         link_bblock (cfg, bblock, tblock);
9837
9838                         if (sp != stack_start) {
9839                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9840                                 CHECK_UNVERIFIABLE (cfg);
9841                         }
9842
9843                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
9844                         cmp->sreg1 = sp [0]->dreg;
9845                         type_from_op (cfg, cmp, sp [0], NULL);
9846                         CHECK_TYPE (cmp);
9847
9848 #if SIZEOF_REGISTER == 4
9849                         if (cmp->opcode == OP_LCOMPARE_IMM) {
9850                                 /* Convert it to OP_LCOMPARE */
9851                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
9852                                 ins->type = STACK_I8;
9853                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
9854                                 ins->inst_l = 0;
9855                                 MONO_ADD_INS (bblock, ins);
9856                                 cmp->opcode = OP_LCOMPARE;
9857                                 cmp->sreg2 = ins->dreg;
9858                         }
9859 #endif
9860                         MONO_ADD_INS (bblock, cmp);
9861
9862                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
9863                         type_from_op (cfg, ins, sp [0], NULL);
9864                         MONO_ADD_INS (bblock, ins);
9865                         ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
9866                         GET_BBLOCK (cfg, tblock, target);
9867                         ins->inst_true_bb = tblock;
9868                         GET_BBLOCK (cfg, tblock, ip);
9869                         ins->inst_false_bb = tblock;
9870                         start_new_bblock = 2;
9871
9872                         sp = stack_start;
9873                         inline_costs += BRANCH_COST;
9874                         break;
9875                 }
9876                 case CEE_BEQ:
9877                 case CEE_BGE:
9878                 case CEE_BGT:
9879                 case CEE_BLE:
9880                 case CEE_BLT:
9881                 case CEE_BNE_UN:
9882                 case CEE_BGE_UN:
9883                 case CEE_BGT_UN:
9884                 case CEE_BLE_UN:
9885                 case CEE_BLT_UN:
9886                         CHECK_OPSIZE (5);
9887                         CHECK_STACK (2);
9888                         MONO_INST_NEW (cfg, ins, *ip);
9889                         ip++;
9890                         target = ip + 4 + (gint32)read32(ip);
9891                         ip += 4;
9892
9893                         ADD_BINCOND (NULL);
9894
9895                         sp = stack_start;
9896                         inline_costs += BRANCH_COST;
9897                         break;
9898                 case CEE_SWITCH: {
9899                         MonoInst *src1;
9900                         MonoBasicBlock **targets;
9901                         MonoBasicBlock *default_bblock;
9902                         MonoJumpInfoBBTable *table;
9903                         int offset_reg = alloc_preg (cfg);
9904                         int target_reg = alloc_preg (cfg);
9905                         int table_reg = alloc_preg (cfg);
9906                         int sum_reg = alloc_preg (cfg);
9907                         gboolean use_op_switch;
9908
9909                         CHECK_OPSIZE (5);
9910                         CHECK_STACK (1);
9911                         n = read32 (ip + 1);
9912                         --sp;
9913                         src1 = sp [0];
9914                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
9915                                 UNVERIFIED;
9916
9917                         ip += 5;
9918                         CHECK_OPSIZE (n * sizeof (guint32));
9919                         target = ip + n * sizeof (guint32);
9920
9921                         GET_BBLOCK (cfg, default_bblock, target);
9922                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
9923
9924                         targets = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
9925                         for (i = 0; i < n; ++i) {
9926                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
9927                                 targets [i] = tblock;
9928                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
9929                                 ip += 4;
9930                         }
9931
9932                         if (sp != stack_start) {
9933                                 /* 
9934                                  * Link the current bb with the targets as well, so handle_stack_args
9935                                  * will set their in_stack correctly.
9936                                  */
9937                                 link_bblock (cfg, bblock, default_bblock);
9938                                 for (i = 0; i < n; ++i)
9939                                         link_bblock (cfg, bblock, targets [i]);
9940
9941                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9942                                 sp = stack_start;
9943                                 CHECK_UNVERIFIABLE (cfg);
9944                         }
9945
9946                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
9947                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
9948                         bblock = cfg->cbb;
9949
9950                         for (i = 0; i < n; ++i)
9951                                 link_bblock (cfg, bblock, targets [i]);
9952
9953                         table = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
9954                         table->table = targets;
9955                         table->table_size = n;
9956
9957                         use_op_switch = FALSE;
9958 #ifdef TARGET_ARM
9959                         /* ARM implements SWITCH statements differently */
9960                         /* FIXME: Make it use the generic implementation */
9961                         if (!cfg->compile_aot)
9962                                 use_op_switch = TRUE;
9963 #endif
9964
9965                         if (COMPILE_LLVM (cfg))
9966                                 use_op_switch = TRUE;
9967
9968                         cfg->cbb->has_jump_table = 1;
9969
9970                         if (use_op_switch) {
9971                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
9972                                 ins->sreg1 = src1->dreg;
9973                                 ins->inst_p0 = table;
9974                                 ins->inst_many_bb = targets;
9975                                 ins->klass = GUINT_TO_POINTER (n);
9976                                 MONO_ADD_INS (cfg->cbb, ins);
9977                         } else {
9978                                 if (sizeof (gpointer) == 8)
9979                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
9980                                 else
9981                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
9982
9983 #if SIZEOF_REGISTER == 8
9984                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
9985                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
9986 #endif
9987
9988                                 if (cfg->compile_aot) {
9989                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
9990                                 } else {
9991                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
9992                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
9993                                         ins->inst_p0 = table;
9994                                         ins->dreg = table_reg;
9995                                         MONO_ADD_INS (cfg->cbb, ins);
9996                                 }
9997
9998                                 /* FIXME: Use load_memindex */
9999                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
10000                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
10001                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
10002                         }
10003                         start_new_bblock = 1;
10004                         inline_costs += (BRANCH_COST * 2);
10005                         break;
10006                 }
10007                 case CEE_LDIND_I1:
10008                 case CEE_LDIND_U1:
10009                 case CEE_LDIND_I2:
10010                 case CEE_LDIND_U2:
10011                 case CEE_LDIND_I4:
10012                 case CEE_LDIND_U4:
10013                 case CEE_LDIND_I8:
10014                 case CEE_LDIND_I:
10015                 case CEE_LDIND_R4:
10016                 case CEE_LDIND_R8:
10017                 case CEE_LDIND_REF:
10018                         CHECK_STACK (1);
10019                         --sp;
10020
10021                         switch (*ip) {
10022                         case CEE_LDIND_R4:
10023                         case CEE_LDIND_R8:
10024                                 dreg = alloc_freg (cfg);
10025                                 break;
10026                         case CEE_LDIND_I8:
10027                                 dreg = alloc_lreg (cfg);
10028                                 break;
10029                         case CEE_LDIND_REF:
10030                                 dreg = alloc_ireg_ref (cfg);
10031                                 break;
10032                         default:
10033                                 dreg = alloc_preg (cfg);
10034                         }
10035
10036                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
10037                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
10038                         if (*ip == CEE_LDIND_R4)
10039                                 ins->type = cfg->r4_stack_type;
10040                         ins->flags |= ins_flag;
10041                         MONO_ADD_INS (bblock, ins);
10042                         *sp++ = ins;
10043                         if (ins_flag & MONO_INST_VOLATILE) {
10044                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10045                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10046                         }
10047                         ins_flag = 0;
10048                         ++ip;
10049                         break;
10050                 case CEE_STIND_REF:
10051                 case CEE_STIND_I1:
10052                 case CEE_STIND_I2:
10053                 case CEE_STIND_I4:
10054                 case CEE_STIND_I8:
10055                 case CEE_STIND_R4:
10056                 case CEE_STIND_R8:
10057                 case CEE_STIND_I:
10058                         CHECK_STACK (2);
10059                         sp -= 2;
10060
10061                         if (ins_flag & MONO_INST_VOLATILE) {
10062                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
10063                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
10064                         }
10065
10066                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
10067                         ins->flags |= ins_flag;
10068                         ins_flag = 0;
10069
10070                         MONO_ADD_INS (bblock, ins);
10071
10072                         if (cfg->gen_write_barriers && *ip == CEE_STIND_REF && method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER && !((sp [1]->opcode == OP_PCONST) && (sp [1]->inst_p0 == 0)))
10073                                 emit_write_barrier (cfg, sp [0], sp [1]);
10074
10075                         inline_costs += 1;
10076                         ++ip;
10077                         break;
10078
10079                 case CEE_MUL:
10080                         CHECK_STACK (2);
10081
10082                         MONO_INST_NEW (cfg, ins, (*ip));
10083                         sp -= 2;
10084                         ins->sreg1 = sp [0]->dreg;
10085                         ins->sreg2 = sp [1]->dreg;
10086                         type_from_op (cfg, ins, sp [0], sp [1]);
10087                         CHECK_TYPE (ins);
10088                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
10089
10090                         /* Use the immediate opcodes if possible */
10091                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
10092                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
10093                                 if (imm_opcode != -1) {
10094                                         ins->opcode = imm_opcode;
10095                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
10096                                         ins->sreg2 = -1;
10097
10098                                         NULLIFY_INS (sp [1]);
10099                                 }
10100                         }
10101
10102                         MONO_ADD_INS ((cfg)->cbb, (ins));
10103
10104                         *sp++ = mono_decompose_opcode (cfg, ins, &bblock);
10105                         ip++;
10106                         break;
10107                 case CEE_ADD:
10108                 case CEE_SUB:
10109                 case CEE_DIV:
10110                 case CEE_DIV_UN:
10111                 case CEE_REM:
10112                 case CEE_REM_UN:
10113                 case CEE_AND:
10114                 case CEE_OR:
10115                 case CEE_XOR:
10116                 case CEE_SHL:
10117                 case CEE_SHR:
10118                 case CEE_SHR_UN:
10119                         CHECK_STACK (2);
10120
10121                         MONO_INST_NEW (cfg, ins, (*ip));
10122                         sp -= 2;
10123                         ins->sreg1 = sp [0]->dreg;
10124                         ins->sreg2 = sp [1]->dreg;
10125                         type_from_op (cfg, ins, sp [0], sp [1]);
10126                         CHECK_TYPE (ins);
10127                         add_widen_op (cfg, ins, &sp [0], &sp [1]);
10128                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
10129
10130                         /* FIXME: Pass opcode to is_inst_imm */
10131
10132                         /* Use the immediate opcodes if possible */
10133                         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)) {
10134                                 int imm_opcode;
10135
10136                                 imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
10137 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
10138                                 /* Keep emulated opcodes which are optimized away later */
10139                                 if ((ins->opcode == OP_IREM_UN || ins->opcode == OP_IDIV_UN_IMM) && (cfg->opt & (MONO_OPT_CONSPROP | MONO_OPT_COPYPROP)) && sp [1]->opcode == OP_ICONST && mono_is_power_of_two (sp [1]->inst_c0) >= 0) {
10140                                         imm_opcode = mono_op_to_op_imm (ins->opcode);
10141                                 }
10142 #endif
10143                                 if (imm_opcode != -1) {
10144                                         ins->opcode = imm_opcode;
10145                                         if (sp [1]->opcode == OP_I8CONST) {
10146 #if SIZEOF_REGISTER == 8
10147                                                 ins->inst_imm = sp [1]->inst_l;
10148 #else
10149                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
10150                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
10151 #endif
10152                                         }
10153                                         else
10154                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
10155                                         ins->sreg2 = -1;
10156
10157                                         /* Might be followed by an instruction added by add_widen_op */
10158                                         if (sp [1]->next == NULL)
10159                                                 NULLIFY_INS (sp [1]);
10160                                 }
10161                         }
10162                         MONO_ADD_INS ((cfg)->cbb, (ins));
10163
10164                         *sp++ = mono_decompose_opcode (cfg, ins, &bblock);
10165                         ip++;
10166                         break;
10167                 case CEE_NEG:
10168                 case CEE_NOT:
10169                 case CEE_CONV_I1:
10170                 case CEE_CONV_I2:
10171                 case CEE_CONV_I4:
10172                 case CEE_CONV_R4:
10173                 case CEE_CONV_R8:
10174                 case CEE_CONV_U4:
10175                 case CEE_CONV_I8:
10176                 case CEE_CONV_U8:
10177                 case CEE_CONV_OVF_I8:
10178                 case CEE_CONV_OVF_U8:
10179                 case CEE_CONV_R_UN:
10180                         CHECK_STACK (1);
10181
10182                         /* Special case this earlier so we have long constants in the IR */
10183                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
10184                                 int data = sp [-1]->inst_c0;
10185                                 sp [-1]->opcode = OP_I8CONST;
10186                                 sp [-1]->type = STACK_I8;
10187 #if SIZEOF_REGISTER == 8
10188                                 if ((*ip) == CEE_CONV_U8)
10189                                         sp [-1]->inst_c0 = (guint32)data;
10190                                 else
10191                                         sp [-1]->inst_c0 = data;
10192 #else
10193                                 sp [-1]->inst_ls_word = data;
10194                                 if ((*ip) == CEE_CONV_U8)
10195                                         sp [-1]->inst_ms_word = 0;
10196                                 else
10197                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
10198 #endif
10199                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
10200                         }
10201                         else {
10202                                 ADD_UNOP (*ip);
10203                         }
10204                         ip++;
10205                         break;
10206                 case CEE_CONV_OVF_I4:
10207                 case CEE_CONV_OVF_I1:
10208                 case CEE_CONV_OVF_I2:
10209                 case CEE_CONV_OVF_I:
10210                 case CEE_CONV_OVF_U:
10211                         CHECK_STACK (1);
10212
10213                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10214                                 ADD_UNOP (CEE_CONV_OVF_I8);
10215                                 ADD_UNOP (*ip);
10216                         } else {
10217                                 ADD_UNOP (*ip);
10218                         }
10219                         ip++;
10220                         break;
10221                 case CEE_CONV_OVF_U1:
10222                 case CEE_CONV_OVF_U2:
10223                 case CEE_CONV_OVF_U4:
10224                         CHECK_STACK (1);
10225
10226                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10227                                 ADD_UNOP (CEE_CONV_OVF_U8);
10228                                 ADD_UNOP (*ip);
10229                         } else {
10230                                 ADD_UNOP (*ip);
10231                         }
10232                         ip++;
10233                         break;
10234                 case CEE_CONV_OVF_I1_UN:
10235                 case CEE_CONV_OVF_I2_UN:
10236                 case CEE_CONV_OVF_I4_UN:
10237                 case CEE_CONV_OVF_I8_UN:
10238                 case CEE_CONV_OVF_U1_UN:
10239                 case CEE_CONV_OVF_U2_UN:
10240                 case CEE_CONV_OVF_U4_UN:
10241                 case CEE_CONV_OVF_U8_UN:
10242                 case CEE_CONV_OVF_I_UN:
10243                 case CEE_CONV_OVF_U_UN:
10244                 case CEE_CONV_U2:
10245                 case CEE_CONV_U1:
10246                 case CEE_CONV_I:
10247                 case CEE_CONV_U:
10248                         CHECK_STACK (1);
10249                         ADD_UNOP (*ip);
10250                         CHECK_CFG_EXCEPTION;
10251                         ip++;
10252                         break;
10253                 case CEE_ADD_OVF:
10254                 case CEE_ADD_OVF_UN:
10255                 case CEE_MUL_OVF:
10256                 case CEE_MUL_OVF_UN:
10257                 case CEE_SUB_OVF:
10258                 case CEE_SUB_OVF_UN:
10259                         CHECK_STACK (2);
10260                         ADD_BINOP (*ip);
10261                         ip++;
10262                         break;
10263                 case CEE_CPOBJ:
10264                         GSHAREDVT_FAILURE (*ip);
10265                         CHECK_OPSIZE (5);
10266                         CHECK_STACK (2);
10267                         token = read32 (ip + 1);
10268                         klass = mini_get_class (method, token, generic_context);
10269                         CHECK_TYPELOAD (klass);
10270                         sp -= 2;
10271                         if (generic_class_is_reference_type (cfg, klass)) {
10272                                 MonoInst *store, *load;
10273                                 int dreg = alloc_ireg_ref (cfg);
10274
10275                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
10276                                 load->flags |= ins_flag;
10277                                 MONO_ADD_INS (cfg->cbb, load);
10278
10279                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
10280                                 store->flags |= ins_flag;
10281                                 MONO_ADD_INS (cfg->cbb, store);
10282
10283                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
10284                                         emit_write_barrier (cfg, sp [0], sp [1]);
10285                         } else {
10286                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10287                         }
10288                         ins_flag = 0;
10289                         ip += 5;
10290                         break;
10291                 case CEE_LDOBJ: {
10292                         int loc_index = -1;
10293                         int stloc_len = 0;
10294
10295                         CHECK_OPSIZE (5);
10296                         CHECK_STACK (1);
10297                         --sp;
10298                         token = read32 (ip + 1);
10299                         klass = mini_get_class (method, token, generic_context);
10300                         CHECK_TYPELOAD (klass);
10301
10302                         /* Optimize the common ldobj+stloc combination */
10303                         switch (ip [5]) {
10304                         case CEE_STLOC_S:
10305                                 loc_index = ip [6];
10306                                 stloc_len = 2;
10307                                 break;
10308                         case CEE_STLOC_0:
10309                         case CEE_STLOC_1:
10310                         case CEE_STLOC_2:
10311                         case CEE_STLOC_3:
10312                                 loc_index = ip [5] - CEE_STLOC_0;
10313                                 stloc_len = 1;
10314                                 break;
10315                         default:
10316                                 break;
10317                         }
10318
10319                         if ((loc_index != -1) && ip_in_bb (cfg, bblock, ip + 5)) {
10320                                 CHECK_LOCAL (loc_index);
10321
10322                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10323                                 ins->dreg = cfg->locals [loc_index]->dreg;
10324                                 ins->flags |= ins_flag;
10325                                 ip += 5;
10326                                 ip += stloc_len;
10327                                 if (ins_flag & MONO_INST_VOLATILE) {
10328                                         /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10329                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10330                                 }
10331                                 ins_flag = 0;
10332                                 break;
10333                         }
10334
10335                         /* Optimize the ldobj+stobj combination */
10336                         /* The reference case ends up being a load+store anyway */
10337                         /* Skip this if the operation is volatile. */
10338                         if (((ip [5] == CEE_STOBJ) && ip_in_bb (cfg, bblock, ip + 5) && read32 (ip + 6) == token) && !generic_class_is_reference_type (cfg, klass) && !(ins_flag & MONO_INST_VOLATILE)) {
10339                                 CHECK_STACK (1);
10340
10341                                 sp --;
10342
10343                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10344
10345                                 ip += 5 + 5;
10346                                 ins_flag = 0;
10347                                 break;
10348                         }
10349
10350                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10351                         ins->flags |= ins_flag;
10352                         *sp++ = ins;
10353
10354                         if (ins_flag & MONO_INST_VOLATILE) {
10355                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10356                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10357                         }
10358
10359                         ip += 5;
10360                         ins_flag = 0;
10361                         inline_costs += 1;
10362                         break;
10363                 }
10364                 case CEE_LDSTR:
10365                         CHECK_STACK_OVF (1);
10366                         CHECK_OPSIZE (5);
10367                         n = read32 (ip + 1);
10368
10369                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
10370                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
10371                                 ins->type = STACK_OBJ;
10372                                 *sp = ins;
10373                         }
10374                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
10375                                 MonoInst *iargs [1];
10376                                 char *str = mono_method_get_wrapper_data (method, n);
10377
10378                                 if (cfg->compile_aot)
10379                                         EMIT_NEW_LDSTRLITCONST (cfg, iargs [0], str);
10380                                 else
10381                                         EMIT_NEW_PCONST (cfg, iargs [0], str);
10382                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
10383                         } else {
10384                                 if (cfg->opt & MONO_OPT_SHARED) {
10385                                         MonoInst *iargs [3];
10386
10387                                         if (cfg->compile_aot) {
10388                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
10389                                         }
10390                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10391                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
10392                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
10393                                         *sp = mono_emit_jit_icall (cfg, mono_ldstr, iargs);
10394                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10395                                 } else {
10396                                         if (bblock->out_of_line) {
10397                                                 MonoInst *iargs [2];
10398
10399                                                 if (image == mono_defaults.corlib) {
10400                                                         /* 
10401                                                          * Avoid relocations in AOT and save some space by using a 
10402                                                          * version of helper_ldstr specialized to mscorlib.
10403                                                          */
10404                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
10405                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
10406                                                 } else {
10407                                                         /* Avoid creating the string object */
10408                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
10409                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
10410                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
10411                                                 }
10412                                         } 
10413                                         else
10414                                         if (cfg->compile_aot) {
10415                                                 NEW_LDSTRCONST (cfg, ins, image, n);
10416                                                 *sp = ins;
10417                                                 MONO_ADD_INS (bblock, ins);
10418                                         } 
10419                                         else {
10420                                                 NEW_PCONST (cfg, ins, NULL);
10421                                                 ins->type = STACK_OBJ;
10422                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10423                                                 if (!ins->inst_p0)
10424                                                         OUT_OF_MEMORY_FAILURE;
10425
10426                                                 *sp = ins;
10427                                                 MONO_ADD_INS (bblock, ins);
10428                                         }
10429                                 }
10430                         }
10431
10432                         sp++;
10433                         ip += 5;
10434                         break;
10435                 case CEE_NEWOBJ: {
10436                         MonoInst *iargs [2];
10437                         MonoMethodSignature *fsig;
10438                         MonoInst this_ins;
10439                         MonoInst *alloc;
10440                         MonoInst *vtable_arg = NULL;
10441
10442                         CHECK_OPSIZE (5);
10443                         token = read32 (ip + 1);
10444                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
10445                         if (!cmethod || mono_loader_get_last_error ())
10446                                 LOAD_ERROR;
10447                         fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
10448                         CHECK_CFG_ERROR;
10449
10450                         mono_save_token_info (cfg, image, token, cmethod);
10451
10452                         if (!mono_class_init (cmethod->klass))
10453                                 TYPE_LOAD_ERROR (cmethod->klass);
10454
10455                         context_used = mini_method_check_context_used (cfg, cmethod);
10456
10457                         if (mono_security_cas_enabled ()) {
10458                                 if (check_linkdemand (cfg, method, cmethod))
10459                                         INLINE_FAILURE ("linkdemand");
10460                                 CHECK_CFG_EXCEPTION;
10461                         } else if (mono_security_core_clr_enabled ()) {
10462                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
10463                         }
10464
10465                         if (cfg->generic_sharing_context && cmethod && cmethod->klass != method->klass && cmethod->klass->generic_class && mono_method_is_generic_sharable (cmethod, TRUE) && mono_class_needs_cctor_run (cmethod->klass, method)) {
10466                                 emit_generic_class_init (cfg, cmethod->klass);
10467                                 CHECK_TYPELOAD (cmethod->klass);
10468                         }
10469
10470                         /*
10471                         if (cfg->gsharedvt) {
10472                                 if (mini_is_gsharedvt_variable_signature (sig))
10473                                         GSHAREDVT_FAILURE (*ip);
10474                         }
10475                         */
10476
10477                         n = fsig->param_count;
10478                         CHECK_STACK (n);
10479
10480                         /* 
10481                          * Generate smaller code for the common newobj <exception> instruction in
10482                          * argument checking code.
10483                          */
10484                         if (bblock->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
10485                                 is_exception_class (cmethod->klass) && n <= 2 &&
10486                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
10487                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
10488                                 MonoInst *iargs [3];
10489
10490                                 sp -= n;
10491
10492                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
10493                                 switch (n) {
10494                                 case 0:
10495                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
10496                                         break;
10497                                 case 1:
10498                                         iargs [1] = sp [0];
10499                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
10500                                         break;
10501                                 case 2:
10502                                         iargs [1] = sp [0];
10503                                         iargs [2] = sp [1];
10504                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
10505                                         break;
10506                                 default:
10507                                         g_assert_not_reached ();
10508                                 }
10509
10510                                 ip += 5;
10511                                 inline_costs += 5;
10512                                 break;
10513                         }
10514
10515                         /* move the args to allow room for 'this' in the first position */
10516                         while (n--) {
10517                                 --sp;
10518                                 sp [1] = sp [0];
10519                         }
10520
10521                         /* check_call_signature () requires sp[0] to be set */
10522                         this_ins.type = STACK_OBJ;
10523                         sp [0] = &this_ins;
10524                         if (check_call_signature (cfg, fsig, sp))
10525                                 UNVERIFIED;
10526
10527                         iargs [0] = NULL;
10528
10529                         if (mini_class_is_system_array (cmethod->klass)) {
10530                                 *sp = emit_get_rgctx_method (cfg, context_used,
10531                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
10532
10533                                 /* Avoid varargs in the common case */
10534                                 if (fsig->param_count == 1)
10535                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
10536                                 else if (fsig->param_count == 2)
10537                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
10538                                 else if (fsig->param_count == 3)
10539                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
10540                                 else if (fsig->param_count == 4)
10541                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
10542                                 else
10543                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
10544                         } else if (cmethod->string_ctor) {
10545                                 g_assert (!context_used);
10546                                 g_assert (!vtable_arg);
10547                                 /* we simply pass a null pointer */
10548                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
10549                                 /* now call the string ctor */
10550                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
10551                         } else {
10552                                 if (cmethod->klass->valuetype) {
10553                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
10554                                         emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
10555                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
10556
10557                                         alloc = NULL;
10558
10559                                         /* 
10560                                          * The code generated by mini_emit_virtual_call () expects
10561                                          * iargs [0] to be a boxed instance, but luckily the vcall
10562                                          * will be transformed into a normal call there.
10563                                          */
10564                                 } else if (context_used) {
10565                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
10566                                         *sp = alloc;
10567                                 } else {
10568                                         MonoVTable *vtable = NULL;
10569
10570                                         if (!cfg->compile_aot)
10571                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
10572                                         CHECK_TYPELOAD (cmethod->klass);
10573
10574                                         /*
10575                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
10576                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
10577                                          * As a workaround, we call class cctors before allocating objects.
10578                                          */
10579                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
10580                                                 mono_emit_abs_call (cfg, MONO_PATCH_INFO_CLASS_INIT, cmethod->klass, helper_sig_class_init_trampoline, NULL);
10581                                                 if (cfg->verbose_level > 2)
10582                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
10583                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
10584                                         }
10585
10586                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
10587                                         *sp = alloc;
10588                                 }
10589                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
10590
10591                                 if (alloc)
10592                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
10593
10594                                 /* Now call the actual ctor */
10595                                 handle_ctor_call (cfg, cmethod, fsig, context_used, sp, ip, &bblock, &inline_costs);
10596                                 CHECK_CFG_EXCEPTION;
10597                         }
10598
10599                         if (alloc == NULL) {
10600                                 /* Valuetype */
10601                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
10602                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
10603                                 *sp++= ins;
10604                         } else {
10605                                 *sp++ = alloc;
10606                         }
10607                         
10608                         ip += 5;
10609                         inline_costs += 5;
10610                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip - header->code)))
10611                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10612                         break;
10613                 }
10614                 case CEE_CASTCLASS:
10615                         CHECK_STACK (1);
10616                         --sp;
10617                         CHECK_OPSIZE (5);
10618                         token = read32 (ip + 1);
10619                         klass = mini_get_class (method, token, generic_context);
10620                         CHECK_TYPELOAD (klass);
10621                         if (sp [0]->type != STACK_OBJ)
10622                                 UNVERIFIED;
10623
10624                         ins = handle_castclass (cfg, klass, *sp, ip, &bblock, &inline_costs);
10625                         CHECK_CFG_EXCEPTION;
10626
10627                         *sp ++ = ins;
10628                         ip += 5;
10629                         break;
10630                 case CEE_ISINST: {
10631                         CHECK_STACK (1);
10632                         --sp;
10633                         CHECK_OPSIZE (5);
10634                         token = read32 (ip + 1);
10635                         klass = mini_get_class (method, token, generic_context);
10636                         CHECK_TYPELOAD (klass);
10637                         if (sp [0]->type != STACK_OBJ)
10638                                 UNVERIFIED;
10639  
10640                         context_used = mini_class_check_context_used (cfg, klass);
10641
10642                         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
10643                                 MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
10644                                 MonoInst *args [3];
10645                                 int idx;
10646
10647                                 /* obj */
10648                                 args [0] = *sp;
10649
10650                                 /* klass */
10651                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
10652
10653                                 /* inline cache*/
10654                                 if (cfg->compile_aot) {
10655                                         idx = get_castclass_cache_idx (cfg);
10656                                         EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
10657                                 } else {
10658                                         EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
10659                                 }
10660
10661                                 *sp++ = mono_emit_method_call (cfg, mono_isinst, args, NULL);
10662                                 ip += 5;
10663                                 inline_costs += 2;
10664                         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
10665                                 MonoMethod *mono_isinst;
10666                                 MonoInst *iargs [1];
10667                                 int costs;
10668
10669                                 mono_isinst = mono_marshal_get_isinst (klass); 
10670                                 iargs [0] = sp [0];
10671
10672                                 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), 
10673                                                                            iargs, ip, cfg->real_offset, TRUE, &bblock);
10674                                 CHECK_CFG_EXCEPTION;
10675                                 g_assert (costs > 0);
10676                                 
10677                                 ip += 5;
10678                                 cfg->real_offset += 5;
10679
10680                                 *sp++= iargs [0];
10681
10682                                 inline_costs += costs;
10683                         }
10684                         else {
10685                                 ins = handle_isinst (cfg, klass, *sp, context_used);
10686                                 CHECK_CFG_EXCEPTION;
10687                                 bblock = cfg->cbb;
10688                                 *sp ++ = ins;
10689                                 ip += 5;
10690                         }
10691                         break;
10692                 }
10693                 case CEE_UNBOX_ANY: {
10694                         MonoInst *res, *addr;
10695
10696                         CHECK_STACK (1);
10697                         --sp;
10698                         CHECK_OPSIZE (5);
10699                         token = read32 (ip + 1);
10700                         klass = mini_get_class (method, token, generic_context);
10701                         CHECK_TYPELOAD (klass);
10702
10703                         mono_save_token_info (cfg, image, token, klass);
10704
10705                         context_used = mini_class_check_context_used (cfg, klass);
10706
10707                         if (mini_is_gsharedvt_klass (cfg, klass)) {
10708                                 res = handle_unbox_gsharedvt (cfg, klass, *sp, &bblock);
10709                                 inline_costs += 2;
10710                         } else if (generic_class_is_reference_type (cfg, klass)) {
10711                                 res = handle_castclass (cfg, klass, *sp, ip, &bblock, &inline_costs);
10712                                 CHECK_CFG_EXCEPTION;
10713                         } else if (mono_class_is_nullable (klass)) {
10714                                 res = handle_unbox_nullable (cfg, *sp, klass, context_used);
10715                         } else {
10716                                 addr = handle_unbox (cfg, klass, sp, context_used);
10717                                 /* LDOBJ */
10718                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
10719                                 res = ins;
10720                                 inline_costs += 2;
10721                         }
10722
10723                         *sp ++ = res;
10724                         ip += 5;
10725                         break;
10726                 }
10727                 case CEE_BOX: {
10728                         MonoInst *val;
10729                         MonoClass *enum_class;
10730                         MonoMethod *has_flag;
10731
10732                         CHECK_STACK (1);
10733                         --sp;
10734                         val = *sp;
10735                         CHECK_OPSIZE (5);
10736                         token = read32 (ip + 1);
10737                         klass = mini_get_class (method, token, generic_context);
10738                         CHECK_TYPELOAD (klass);
10739
10740                         mono_save_token_info (cfg, image, token, klass);
10741
10742                         context_used = mini_class_check_context_used (cfg, klass);
10743
10744                         if (generic_class_is_reference_type (cfg, klass)) {
10745                                 *sp++ = val;
10746                                 ip += 5;
10747                                 break;
10748                         }
10749
10750                         if (klass == mono_defaults.void_class)
10751                                 UNVERIFIED;
10752                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
10753                                 UNVERIFIED;
10754                         /* frequent check in generic code: box (struct), brtrue */
10755
10756                         /*
10757                          * Look for:
10758                          *
10759                          *   <push int/long ptr>
10760                          *   <push int/long>
10761                          *   box MyFlags
10762                          *   constrained. MyFlags
10763                          *   callvirt instace bool class [mscorlib] System.Enum::HasFlag (class [mscorlib] System.Enum)
10764                          *
10765                          * If we find this sequence and the operand types on box and constrained
10766                          * are equal, we can emit a specialized instruction sequence instead of
10767                          * the very slow HasFlag () call.
10768                          */
10769                         if ((cfg->opt & MONO_OPT_INTRINS) &&
10770                             /* Cheap checks first. */
10771                             ip + 5 + 6 + 5 < end &&
10772                             ip [5] == CEE_PREFIX1 &&
10773                             ip [6] == CEE_CONSTRAINED_ &&
10774                             ip [11] == CEE_CALLVIRT &&
10775                             ip_in_bb (cfg, bblock, ip + 5 + 6 + 5) &&
10776                             mono_class_is_enum (klass) &&
10777                             (enum_class = mini_get_class (method, read32 (ip + 7), generic_context)) &&
10778                             (has_flag = mini_get_method (cfg, method, read32 (ip + 12), NULL, generic_context)) &&
10779                             has_flag->klass == mono_defaults.enum_class &&
10780                             !strcmp (has_flag->name, "HasFlag") &&
10781                             has_flag->signature->hasthis &&
10782                             has_flag->signature->param_count == 1) {
10783                                 CHECK_TYPELOAD (enum_class);
10784
10785                                 if (enum_class == klass) {
10786                                         MonoInst *enum_this, *enum_flag;
10787
10788                                         ip += 5 + 6 + 5;
10789                                         --sp;
10790
10791                                         enum_this = sp [0];
10792                                         enum_flag = sp [1];
10793
10794                                         *sp++ = handle_enum_has_flag (cfg, klass, enum_this, enum_flag);
10795                                         break;
10796                                 }
10797                         }
10798
10799                         // FIXME: LLVM can't handle the inconsistent bb linking
10800                         if (!mono_class_is_nullable (klass) &&
10801                                 ip + 5 < end && ip_in_bb (cfg, bblock, ip + 5) &&
10802                                 (ip [5] == CEE_BRTRUE || 
10803                                  ip [5] == CEE_BRTRUE_S ||
10804                                  ip [5] == CEE_BRFALSE ||
10805                                  ip [5] == CEE_BRFALSE_S)) {
10806                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
10807                                 int dreg;
10808                                 MonoBasicBlock *true_bb, *false_bb;
10809
10810                                 ip += 5;
10811
10812                                 if (cfg->verbose_level > 3) {
10813                                         printf ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
10814                                         printf ("<box+brtrue opt>\n");
10815                                 }
10816
10817                                 switch (*ip) {
10818                                 case CEE_BRTRUE_S:
10819                                 case CEE_BRFALSE_S:
10820                                         CHECK_OPSIZE (2);
10821                                         ip++;
10822                                         target = ip + 1 + (signed char)(*ip);
10823                                         ip++;
10824                                         break;
10825                                 case CEE_BRTRUE:
10826                                 case CEE_BRFALSE:
10827                                         CHECK_OPSIZE (5);
10828                                         ip++;
10829                                         target = ip + 4 + (gint)(read32 (ip));
10830                                         ip += 4;
10831                                         break;
10832                                 default:
10833                                         g_assert_not_reached ();
10834                                 }
10835
10836                                 /* 
10837                                  * We need to link both bblocks, since it is needed for handling stack
10838                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
10839                                  * Branching to only one of them would lead to inconsistencies, so
10840                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
10841                                  */
10842                                 GET_BBLOCK (cfg, true_bb, target);
10843                                 GET_BBLOCK (cfg, false_bb, ip);
10844
10845                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
10846                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
10847
10848                                 if (sp != stack_start) {
10849                                         handle_stack_args (cfg, stack_start, sp - stack_start);
10850                                         sp = stack_start;
10851                                         CHECK_UNVERIFIABLE (cfg);
10852                                 }
10853
10854                                 if (COMPILE_LLVM (cfg)) {
10855                                         dreg = alloc_ireg (cfg);
10856                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
10857                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
10858
10859                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
10860                                 } else {
10861                                         /* The JIT can't eliminate the iconst+compare */
10862                                         MONO_INST_NEW (cfg, ins, OP_BR);
10863                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
10864                                         MONO_ADD_INS (cfg->cbb, ins);
10865                                 }
10866
10867                                 start_new_bblock = 1;
10868                                 break;
10869                         }
10870
10871                         *sp++ = handle_box (cfg, val, klass, context_used, &bblock);
10872
10873                         CHECK_CFG_EXCEPTION;
10874                         ip += 5;
10875                         inline_costs += 1;
10876                         break;
10877                 }
10878                 case CEE_UNBOX: {
10879                         CHECK_STACK (1);
10880                         --sp;
10881                         CHECK_OPSIZE (5);
10882                         token = read32 (ip + 1);
10883                         klass = mini_get_class (method, token, generic_context);
10884                         CHECK_TYPELOAD (klass);
10885
10886                         mono_save_token_info (cfg, image, token, klass);
10887
10888                         context_used = mini_class_check_context_used (cfg, klass);
10889
10890                         if (mono_class_is_nullable (klass)) {
10891                                 MonoInst *val;
10892
10893                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
10894                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
10895
10896                                 *sp++= ins;
10897                         } else {
10898                                 ins = handle_unbox (cfg, klass, sp, context_used);
10899                                 *sp++ = ins;
10900                         }
10901                         ip += 5;
10902                         inline_costs += 2;
10903                         break;
10904                 }
10905                 case CEE_LDFLD:
10906                 case CEE_LDFLDA:
10907                 case CEE_STFLD:
10908                 case CEE_LDSFLD:
10909                 case CEE_LDSFLDA:
10910                 case CEE_STSFLD: {
10911                         MonoClassField *field;
10912 #ifndef DISABLE_REMOTING
10913                         int costs;
10914 #endif
10915                         guint foffset;
10916                         gboolean is_instance;
10917                         int op;
10918                         gpointer addr = NULL;
10919                         gboolean is_special_static;
10920                         MonoType *ftype;
10921                         MonoInst *store_val = NULL;
10922                         MonoInst *thread_ins;
10923
10924                         op = *ip;
10925                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
10926                         if (is_instance) {
10927                                 if (op == CEE_STFLD) {
10928                                         CHECK_STACK (2);
10929                                         sp -= 2;
10930                                         store_val = sp [1];
10931                                 } else {
10932                                         CHECK_STACK (1);
10933                                         --sp;
10934                                 }
10935                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
10936                                         UNVERIFIED;
10937                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
10938                                         UNVERIFIED;
10939                         } else {
10940                                 if (op == CEE_STSFLD) {
10941                                         CHECK_STACK (1);
10942                                         sp--;
10943                                         store_val = sp [0];
10944                                 }
10945                         }
10946
10947                         CHECK_OPSIZE (5);
10948                         token = read32 (ip + 1);
10949                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
10950                                 field = mono_method_get_wrapper_data (method, token);
10951                                 klass = field->parent;
10952                         }
10953                         else {
10954                                 field = mono_field_from_token_checked (image, token, &klass, generic_context, &cfg->error);
10955                                 CHECK_CFG_ERROR;
10956                         }
10957                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
10958                                 FIELD_ACCESS_FAILURE (method, field);
10959                         mono_class_init (klass);
10960
10961                         if (is_instance && *ip != CEE_LDFLDA && is_magic_tls_access (field))
10962                                 UNVERIFIED;
10963
10964                         /* if the class is Critical then transparent code cannot access it's fields */
10965                         if (!is_instance && mono_security_core_clr_enabled ())
10966                                 ensure_method_is_allowed_to_access_field (cfg, method, field, bblock, ip);
10967
10968                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
10969                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
10970                         if (mono_security_core_clr_enabled ())
10971                                 ensure_method_is_allowed_to_access_field (cfg, method, field, bblock, ip);
10972                         */
10973
10974                         /*
10975                          * LDFLD etc. is usable on static fields as well, so convert those cases to
10976                          * the static case.
10977                          */
10978                         if (is_instance && field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
10979                                 switch (op) {
10980                                 case CEE_LDFLD:
10981                                         op = CEE_LDSFLD;
10982                                         break;
10983                                 case CEE_STFLD:
10984                                         op = CEE_STSFLD;
10985                                         break;
10986                                 case CEE_LDFLDA:
10987                                         op = CEE_LDSFLDA;
10988                                         break;
10989                                 default:
10990                                         g_assert_not_reached ();
10991                                 }
10992                                 is_instance = FALSE;
10993                         }
10994
10995                         context_used = mini_class_check_context_used (cfg, klass);
10996
10997                         /* INSTANCE CASE */
10998
10999                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
11000                         if (op == CEE_STFLD) {
11001                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
11002                                         UNVERIFIED;
11003 #ifndef DISABLE_REMOTING
11004                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
11005                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
11006                                         MonoInst *iargs [5];
11007
11008                                         GSHAREDVT_FAILURE (op);
11009
11010                                         iargs [0] = sp [0];
11011                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11012                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
11013                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
11014                                                     field->offset);
11015                                         iargs [4] = sp [1];
11016
11017                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
11018                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
11019                                                                                            iargs, ip, cfg->real_offset, TRUE, &bblock);
11020                                                 CHECK_CFG_EXCEPTION;
11021                                                 g_assert (costs > 0);
11022                                                       
11023                                                 cfg->real_offset += 5;
11024
11025                                                 inline_costs += costs;
11026                                         } else {
11027                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
11028                                         }
11029                                 } else
11030 #endif
11031                                 {
11032                                         MonoInst *store;
11033
11034                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
11035
11036                                         if (mini_is_gsharedvt_klass (cfg, klass)) {
11037                                                 MonoInst *offset_ins;
11038
11039                                                 context_used = mini_class_check_context_used (cfg, klass);
11040
11041                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11042                                                 dreg = alloc_ireg_mp (cfg);
11043                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11044                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
11045                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
11046                                         } else {
11047                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
11048                                         }
11049                                         if (sp [0]->opcode != OP_LDADDR)
11050                                                 store->flags |= MONO_INST_FAULT;
11051
11052                                 if (cfg->gen_write_barriers && mini_type_to_stind (cfg, field->type) == CEE_STIND_REF && !(sp [1]->opcode == OP_PCONST && sp [1]->inst_c0 == 0)) {
11053                                         /* insert call to write barrier */
11054                                         MonoInst *ptr;
11055                                         int dreg;
11056
11057                                         dreg = alloc_ireg_mp (cfg);
11058                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
11059                                         emit_write_barrier (cfg, ptr, sp [1]);
11060                                 }
11061
11062                                         store->flags |= ins_flag;
11063                                 }
11064                                 ins_flag = 0;
11065                                 ip += 5;
11066                                 break;
11067                         }
11068
11069 #ifndef DISABLE_REMOTING
11070                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
11071                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
11072                                 MonoInst *iargs [4];
11073
11074                                 GSHAREDVT_FAILURE (op);
11075
11076                                 iargs [0] = sp [0];
11077                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11078                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
11079                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
11080                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
11081                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
11082                                                                                    iargs, ip, cfg->real_offset, TRUE, &bblock);
11083                                         CHECK_CFG_EXCEPTION;
11084                                         g_assert (costs > 0);
11085                                                       
11086                                         cfg->real_offset += 5;
11087
11088                                         *sp++ = iargs [0];
11089
11090                                         inline_costs += costs;
11091                                 } else {
11092                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
11093                                         *sp++ = ins;
11094                                 }
11095                         } else 
11096 #endif
11097                         if (is_instance) {
11098                                 if (sp [0]->type == STACK_VTYPE) {
11099                                         MonoInst *var;
11100
11101                                         /* Have to compute the address of the variable */
11102
11103                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
11104                                         if (!var)
11105                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
11106                                         else
11107                                                 g_assert (var->klass == klass);
11108                                         
11109                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
11110                                         sp [0] = ins;
11111                                 }
11112
11113                                 if (op == CEE_LDFLDA) {
11114                                         if (is_magic_tls_access (field)) {
11115                                                 GSHAREDVT_FAILURE (*ip);
11116                                                 ins = sp [0];
11117                                                 *sp++ = create_magic_tls_access (cfg, field, &cached_tls_addr, ins);
11118                                         } else {
11119                                                 if (sp [0]->type == STACK_OBJ) {
11120                                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
11121                                                         MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
11122                                                 }
11123
11124                                                 dreg = alloc_ireg_mp (cfg);
11125
11126                                                 if (mini_is_gsharedvt_klass (cfg, klass)) {
11127                                                         MonoInst *offset_ins;
11128
11129                                                         offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11130                                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11131                                                 } else {
11132                                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
11133                                                 }
11134                                                 ins->klass = mono_class_from_mono_type (field->type);
11135                                                 ins->type = STACK_MP;
11136                                                 *sp++ = ins;
11137                                         }
11138                                 } else {
11139                                         MonoInst *load;
11140
11141                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
11142
11143                                         if (mini_is_gsharedvt_klass (cfg, klass)) {
11144                                                 MonoInst *offset_ins;
11145
11146                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11147                                                 dreg = alloc_ireg_mp (cfg);
11148                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11149                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
11150                                         } else {
11151                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
11152                                         }
11153                                         load->flags |= ins_flag;
11154                                         if (sp [0]->opcode != OP_LDADDR)
11155                                                 load->flags |= MONO_INST_FAULT;
11156                                         *sp++ = load;
11157                                 }
11158                         }
11159
11160                         if (is_instance) {
11161                                 ins_flag = 0;
11162                                 ip += 5;
11163                                 break;
11164                         }
11165
11166                         /* STATIC CASE */
11167
11168                         /*
11169                          * We can only support shared generic static
11170                          * field access on architectures where the
11171                          * trampoline code has been extended to handle
11172                          * the generic class init.
11173                          */
11174 #ifndef MONO_ARCH_VTABLE_REG
11175                         GENERIC_SHARING_FAILURE (op);
11176 #endif
11177
11178                         context_used = mini_class_check_context_used (cfg, klass);
11179
11180                         ftype = mono_field_get_type (field);
11181
11182                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL)
11183                                 UNVERIFIED;
11184
11185                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
11186                          * to be called here.
11187                          */
11188                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
11189                                 mono_class_vtable (cfg->domain, klass);
11190                                 CHECK_TYPELOAD (klass);
11191                         }
11192                         mono_domain_lock (cfg->domain);
11193                         if (cfg->domain->special_static_fields)
11194                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
11195                         mono_domain_unlock (cfg->domain);
11196
11197                         is_special_static = mono_class_field_is_special_static (field);
11198
11199                         if (is_special_static && ((gsize)addr & 0x80000000) == 0)
11200                                 thread_ins = mono_get_thread_intrinsic (cfg);
11201                         else
11202                                 thread_ins = NULL;
11203
11204                         /* Generate IR to compute the field address */
11205                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
11206                                 /*
11207                                  * Fast access to TLS data
11208                                  * Inline version of get_thread_static_data () in
11209                                  * threads.c.
11210                                  */
11211                                 guint32 offset;
11212                                 int idx, static_data_reg, array_reg, dreg;
11213
11214                                 GSHAREDVT_FAILURE (op);
11215
11216                                 // offset &= 0x7fffffff;
11217                                 // idx = (offset >> 24) - 1;
11218                                 //      return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
11219                                 MONO_ADD_INS (cfg->cbb, thread_ins);
11220                                 static_data_reg = alloc_ireg (cfg);
11221                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
11222
11223                                 if (cfg->compile_aot) {
11224                                         int offset_reg, offset2_reg, idx_reg;
11225
11226                                         /* For TLS variables, this will return the TLS offset */
11227                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
11228                                         offset_reg = ins->dreg;
11229                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
11230                                         idx_reg = alloc_ireg (cfg);
11231                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_IMM, idx_reg, offset_reg, 24);
11232                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, idx_reg, idx_reg, 1);
11233                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
11234                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
11235                                         array_reg = alloc_ireg (cfg);
11236                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
11237                                         offset2_reg = alloc_ireg (cfg);
11238                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset_reg, 0xffffff);
11239                                         dreg = alloc_ireg (cfg);
11240                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
11241                                 } else {
11242                                         offset = (gsize)addr & 0x7fffffff;
11243                                         idx = (offset >> 24) - 1;
11244
11245                                         array_reg = alloc_ireg (cfg);
11246                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
11247                                         dreg = alloc_ireg (cfg);
11248                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, (offset & 0xffffff));
11249                                 }
11250                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
11251                                         (cfg->compile_aot && is_special_static) ||
11252                                         (context_used && is_special_static)) {
11253                                 MonoInst *iargs [2];
11254
11255                                 g_assert (field->parent);
11256                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11257                                 if (context_used) {
11258                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
11259                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
11260                                 } else {
11261                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11262                                 }
11263                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11264                         } else if (context_used) {
11265                                 MonoInst *static_data;
11266
11267                                 /*
11268                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
11269                                         method->klass->name_space, method->klass->name, method->name,
11270                                         depth, field->offset);
11271                                 */
11272
11273                                 if (mono_class_needs_cctor_run (klass, method))
11274                                         emit_generic_class_init (cfg, klass);
11275
11276                                 /*
11277                                  * The pointer we're computing here is
11278                                  *
11279                                  *   super_info.static_data + field->offset
11280                                  */
11281                                 static_data = emit_get_rgctx_klass (cfg, context_used,
11282                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
11283
11284                                 if (mini_is_gsharedvt_klass (cfg, klass)) {
11285                                         MonoInst *offset_ins;
11286
11287                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11288                                         dreg = alloc_ireg_mp (cfg);
11289                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
11290                                 } else if (field->offset == 0) {
11291                                         ins = static_data;
11292                                 } else {
11293                                         int addr_reg = mono_alloc_preg (cfg);
11294                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
11295                                 }
11296                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
11297                                 MonoInst *iargs [2];
11298
11299                                 g_assert (field->parent);
11300                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11301                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11302                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11303                         } else {
11304                                 MonoVTable *vtable = NULL;
11305
11306                                 if (!cfg->compile_aot)
11307                                         vtable = mono_class_vtable (cfg->domain, klass);
11308                                 CHECK_TYPELOAD (klass);
11309
11310                                 if (!addr) {
11311                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
11312                                                 if (!(g_slist_find (class_inits, klass))) {
11313                                                         mono_emit_abs_call (cfg, MONO_PATCH_INFO_CLASS_INIT, klass, helper_sig_class_init_trampoline, NULL);
11314                                                         if (cfg->verbose_level > 2)
11315                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
11316                                                         class_inits = g_slist_prepend (class_inits, klass);
11317                                                 }
11318                                         } else {
11319                                                 if (cfg->run_cctors) {
11320                                                         MonoException *ex;
11321                                                         /* This makes so that inline cannot trigger */
11322                                                         /* .cctors: too many apps depend on them */
11323                                                         /* running with a specific order... */
11324                                                         g_assert (vtable);
11325                                                         if (! vtable->initialized)
11326                                                                 INLINE_FAILURE ("class init");
11327                                                         ex = mono_runtime_class_init_full (vtable, FALSE);
11328                                                         if (ex) {
11329                                                                 set_exception_object (cfg, ex);
11330                                                                 goto exception_exit;
11331                                                         }
11332                                                 }
11333                                         }
11334                                         if (cfg->compile_aot)
11335                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
11336                                         else {
11337                                                 g_assert (vtable);
11338                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11339                                                 g_assert (addr);
11340                                                 EMIT_NEW_PCONST (cfg, ins, addr);
11341                                         }
11342                                 } else {
11343                                         MonoInst *iargs [1];
11344                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
11345                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
11346                                 }
11347                         }
11348
11349                         /* Generate IR to do the actual load/store operation */
11350
11351                         if ((op == CEE_STFLD || op == CEE_STSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11352                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11353                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11354                         }
11355
11356                         if (op == CEE_LDSFLDA) {
11357                                 ins->klass = mono_class_from_mono_type (ftype);
11358                                 ins->type = STACK_PTR;
11359                                 *sp++ = ins;
11360                         } else if (op == CEE_STSFLD) {
11361                                 MonoInst *store;
11362
11363                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
11364                                 store->flags |= ins_flag;
11365                         } else {
11366                                 gboolean is_const = FALSE;
11367                                 MonoVTable *vtable = NULL;
11368                                 gpointer addr = NULL;
11369
11370                                 if (!context_used) {
11371                                         vtable = mono_class_vtable (cfg->domain, klass);
11372                                         CHECK_TYPELOAD (klass);
11373                                 }
11374                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
11375                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
11376                                         int ro_type = ftype->type;
11377                                         if (!addr)
11378                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11379                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
11380                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
11381                                         }
11382
11383                                         GSHAREDVT_FAILURE (op);
11384
11385                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
11386                                         is_const = TRUE;
11387                                         switch (ro_type) {
11388                                         case MONO_TYPE_BOOLEAN:
11389                                         case MONO_TYPE_U1:
11390                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
11391                                                 sp++;
11392                                                 break;
11393                                         case MONO_TYPE_I1:
11394                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
11395                                                 sp++;
11396                                                 break;                                          
11397                                         case MONO_TYPE_CHAR:
11398                                         case MONO_TYPE_U2:
11399                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
11400                                                 sp++;
11401                                                 break;
11402                                         case MONO_TYPE_I2:
11403                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
11404                                                 sp++;
11405                                                 break;
11406                                                 break;
11407                                         case MONO_TYPE_I4:
11408                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
11409                                                 sp++;
11410                                                 break;                                          
11411                                         case MONO_TYPE_U4:
11412                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
11413                                                 sp++;
11414                                                 break;
11415                                         case MONO_TYPE_I:
11416                                         case MONO_TYPE_U:
11417                                         case MONO_TYPE_PTR:
11418                                         case MONO_TYPE_FNPTR:
11419                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11420                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
11421                                                 sp++;
11422                                                 break;
11423                                         case MONO_TYPE_STRING:
11424                                         case MONO_TYPE_OBJECT:
11425                                         case MONO_TYPE_CLASS:
11426                                         case MONO_TYPE_SZARRAY:
11427                                         case MONO_TYPE_ARRAY:
11428                                                 if (!mono_gc_is_moving ()) {
11429                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11430                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
11431                                                         sp++;
11432                                                 } else {
11433                                                         is_const = FALSE;
11434                                                 }
11435                                                 break;
11436                                         case MONO_TYPE_I8:
11437                                         case MONO_TYPE_U8:
11438                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
11439                                                 sp++;
11440                                                 break;
11441                                         case MONO_TYPE_R4:
11442                                         case MONO_TYPE_R8:
11443                                         case MONO_TYPE_VALUETYPE:
11444                                         default:
11445                                                 is_const = FALSE;
11446                                                 break;
11447                                         }
11448                                 }
11449
11450                                 if (!is_const) {
11451                                         MonoInst *load;
11452
11453                                         CHECK_STACK_OVF (1);
11454
11455                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
11456                                         load->flags |= ins_flag;
11457                                         ins_flag = 0;
11458                                         *sp++ = load;
11459                                 }
11460                         }
11461
11462                         if ((op == CEE_LDFLD || op == CEE_LDSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11463                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
11464                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
11465                         }
11466
11467                         ins_flag = 0;
11468                         ip += 5;
11469                         break;
11470                 }
11471                 case CEE_STOBJ:
11472                         CHECK_STACK (2);
11473                         sp -= 2;
11474                         CHECK_OPSIZE (5);
11475                         token = read32 (ip + 1);
11476                         klass = mini_get_class (method, token, generic_context);
11477                         CHECK_TYPELOAD (klass);
11478                         if (ins_flag & MONO_INST_VOLATILE) {
11479                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11480                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11481                         }
11482                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
11483                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
11484                         ins->flags |= ins_flag;
11485                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
11486                                         generic_class_is_reference_type (cfg, klass)) {
11487                                 /* insert call to write barrier */
11488                                 emit_write_barrier (cfg, sp [0], sp [1]);
11489                         }
11490                         ins_flag = 0;
11491                         ip += 5;
11492                         inline_costs += 1;
11493                         break;
11494
11495                         /*
11496                          * Array opcodes
11497                          */
11498                 case CEE_NEWARR: {
11499                         MonoInst *len_ins;
11500                         const char *data_ptr;
11501                         int data_size = 0;
11502                         guint32 field_token;
11503
11504                         CHECK_STACK (1);
11505                         --sp;
11506
11507                         CHECK_OPSIZE (5);
11508                         token = read32 (ip + 1);
11509
11510                         klass = mini_get_class (method, token, generic_context);
11511                         CHECK_TYPELOAD (klass);
11512
11513                         context_used = mini_class_check_context_used (cfg, klass);
11514
11515                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
11516                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
11517                                 ins->sreg1 = sp [0]->dreg;
11518                                 ins->type = STACK_I4;
11519                                 ins->dreg = alloc_ireg (cfg);
11520                                 MONO_ADD_INS (cfg->cbb, ins);
11521                                 *sp = mono_decompose_opcode (cfg, ins, &bblock);
11522                         }
11523
11524                         if (context_used) {
11525                                 MonoInst *args [3];
11526                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11527                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
11528
11529                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
11530
11531                                 /* vtable */
11532                                 args [0] = emit_get_rgctx_klass (cfg, context_used,
11533                                         array_class, MONO_RGCTX_INFO_VTABLE);
11534                                 /* array len */
11535                                 args [1] = sp [0];
11536
11537                                 if (managed_alloc)
11538                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
11539                                 else
11540                                         ins = mono_emit_jit_icall (cfg, mono_array_new_specific, args);
11541                         } else {
11542                                 if (cfg->opt & MONO_OPT_SHARED) {
11543                                         /* Decompose now to avoid problems with references to the domainvar */
11544                                         MonoInst *iargs [3];
11545
11546                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11547                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11548                                         iargs [2] = sp [0];
11549
11550                                         ins = mono_emit_jit_icall (cfg, mono_array_new, iargs);
11551                                 } else {
11552                                         /* Decompose later since it is needed by abcrem */
11553                                         MonoClass *array_type = mono_array_class_get (klass, 1);
11554                                         mono_class_vtable (cfg->domain, array_type);
11555                                         CHECK_TYPELOAD (array_type);
11556
11557                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
11558                                         ins->dreg = alloc_ireg_ref (cfg);
11559                                         ins->sreg1 = sp [0]->dreg;
11560                                         ins->inst_newa_class = klass;
11561                                         ins->type = STACK_OBJ;
11562                                         ins->klass = array_type;
11563                                         MONO_ADD_INS (cfg->cbb, ins);
11564                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11565                                         cfg->cbb->has_array_access = TRUE;
11566
11567                                         /* Needed so mono_emit_load_get_addr () gets called */
11568                                         mono_get_got_var (cfg);
11569                                 }
11570                         }
11571
11572                         len_ins = sp [0];
11573                         ip += 5;
11574                         *sp++ = ins;
11575                         inline_costs += 1;
11576
11577                         /* 
11578                          * we inline/optimize the initialization sequence if possible.
11579                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
11580                          * for small sizes open code the memcpy
11581                          * ensure the rva field is big enough
11582                          */
11583                         if ((cfg->opt & MONO_OPT_INTRINS) && ip + 6 < end && ip_in_bb (cfg, bblock, 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))) {
11584                                 MonoMethod *memcpy_method = get_memcpy_method ();
11585                                 MonoInst *iargs [3];
11586                                 int add_reg = alloc_ireg_mp (cfg);
11587
11588                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, MONO_STRUCT_OFFSET (MonoArray, vector));
11589                                 if (cfg->compile_aot) {
11590                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
11591                                 } else {
11592                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
11593                                 }
11594                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
11595                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
11596                                 ip += 11;
11597                         }
11598
11599                         break;
11600                 }
11601                 case CEE_LDLEN:
11602                         CHECK_STACK (1);
11603                         --sp;
11604                         if (sp [0]->type != STACK_OBJ)
11605                                 UNVERIFIED;
11606
11607                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
11608                         ins->dreg = alloc_preg (cfg);
11609                         ins->sreg1 = sp [0]->dreg;
11610                         ins->type = STACK_I4;
11611                         /* This flag will be inherited by the decomposition */
11612                         ins->flags |= MONO_INST_FAULT;
11613                         MONO_ADD_INS (cfg->cbb, ins);
11614                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11615                         cfg->cbb->has_array_access = TRUE;
11616                         ip ++;
11617                         *sp++ = ins;
11618                         break;
11619                 case CEE_LDELEMA:
11620                         CHECK_STACK (2);
11621                         sp -= 2;
11622                         CHECK_OPSIZE (5);
11623                         if (sp [0]->type != STACK_OBJ)
11624                                 UNVERIFIED;
11625
11626                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11627
11628                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11629                         CHECK_TYPELOAD (klass);
11630                         /* we need to make sure that this array is exactly the type it needs
11631                          * to be for correctness. the wrappers are lax with their usage
11632                          * so we need to ignore them here
11633                          */
11634                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
11635                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11636                                 mini_emit_check_array_type (cfg, sp [0], array_class);
11637                                 CHECK_TYPELOAD (array_class);
11638                         }
11639
11640                         readonly = FALSE;
11641                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11642                         *sp++ = ins;
11643                         ip += 5;
11644                         break;
11645                 case CEE_LDELEM:
11646                 case CEE_LDELEM_I1:
11647                 case CEE_LDELEM_U1:
11648                 case CEE_LDELEM_I2:
11649                 case CEE_LDELEM_U2:
11650                 case CEE_LDELEM_I4:
11651                 case CEE_LDELEM_U4:
11652                 case CEE_LDELEM_I8:
11653                 case CEE_LDELEM_I:
11654                 case CEE_LDELEM_R4:
11655                 case CEE_LDELEM_R8:
11656                 case CEE_LDELEM_REF: {
11657                         MonoInst *addr;
11658
11659                         CHECK_STACK (2);
11660                         sp -= 2;
11661
11662                         if (*ip == CEE_LDELEM) {
11663                                 CHECK_OPSIZE (5);
11664                                 token = read32 (ip + 1);
11665                                 klass = mini_get_class (method, token, generic_context);
11666                                 CHECK_TYPELOAD (klass);
11667                                 mono_class_init (klass);
11668                         }
11669                         else
11670                                 klass = array_access_to_klass (*ip);
11671
11672                         if (sp [0]->type != STACK_OBJ)
11673                                 UNVERIFIED;
11674
11675                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11676
11677                         if (mini_is_gsharedvt_variable_klass (cfg, klass)) {
11678                                 // FIXME-VT: OP_ICONST optimization
11679                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11680                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11681                                 ins->opcode = OP_LOADV_MEMBASE;
11682                         } else if (sp [1]->opcode == OP_ICONST) {
11683                                 int array_reg = sp [0]->dreg;
11684                                 int index_reg = sp [1]->dreg;
11685                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
11686
11687                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
11688                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
11689                         } else {
11690                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11691                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11692                         }
11693                         *sp++ = ins;
11694                         if (*ip == CEE_LDELEM)
11695                                 ip += 5;
11696                         else
11697                                 ++ip;
11698                         break;
11699                 }
11700                 case CEE_STELEM_I:
11701                 case CEE_STELEM_I1:
11702                 case CEE_STELEM_I2:
11703                 case CEE_STELEM_I4:
11704                 case CEE_STELEM_I8:
11705                 case CEE_STELEM_R4:
11706                 case CEE_STELEM_R8:
11707                 case CEE_STELEM_REF:
11708                 case CEE_STELEM: {
11709                         CHECK_STACK (3);
11710                         sp -= 3;
11711
11712                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11713
11714                         if (*ip == CEE_STELEM) {
11715                                 CHECK_OPSIZE (5);
11716                                 token = read32 (ip + 1);
11717                                 klass = mini_get_class (method, token, generic_context);
11718                                 CHECK_TYPELOAD (klass);
11719                                 mono_class_init (klass);
11720                         }
11721                         else
11722                                 klass = array_access_to_klass (*ip);
11723
11724                         if (sp [0]->type != STACK_OBJ)
11725                                 UNVERIFIED;
11726
11727                         emit_array_store (cfg, klass, sp, TRUE);
11728
11729                         if (*ip == CEE_STELEM)
11730                                 ip += 5;
11731                         else
11732                                 ++ip;
11733                         inline_costs += 1;
11734                         break;
11735                 }
11736                 case CEE_CKFINITE: {
11737                         CHECK_STACK (1);
11738                         --sp;
11739
11740                         MONO_INST_NEW (cfg, ins, OP_CKFINITE);
11741                         ins->sreg1 = sp [0]->dreg;
11742                         ins->dreg = alloc_freg (cfg);
11743                         ins->type = STACK_R8;
11744                         MONO_ADD_INS (bblock, ins);
11745
11746                         *sp++ = mono_decompose_opcode (cfg, ins, &bblock);
11747
11748                         ++ip;
11749                         break;
11750                 }
11751                 case CEE_REFANYVAL: {
11752                         MonoInst *src_var, *src;
11753
11754                         int klass_reg = alloc_preg (cfg);
11755                         int dreg = alloc_preg (cfg);
11756
11757                         GSHAREDVT_FAILURE (*ip);
11758
11759                         CHECK_STACK (1);
11760                         MONO_INST_NEW (cfg, ins, *ip);
11761                         --sp;
11762                         CHECK_OPSIZE (5);
11763                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11764                         CHECK_TYPELOAD (klass);
11765
11766                         context_used = mini_class_check_context_used (cfg, klass);
11767
11768                         // FIXME:
11769                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11770                         if (!src_var)
11771                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
11772                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
11773                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass));
11774
11775                         if (context_used) {
11776                                 MonoInst *klass_ins;
11777
11778                                 klass_ins = emit_get_rgctx_klass (cfg, context_used,
11779                                                 klass, MONO_RGCTX_INFO_KLASS);
11780
11781                                 // FIXME:
11782                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
11783                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
11784                         } else {
11785                                 mini_emit_class_check (cfg, klass_reg, klass);
11786                         }
11787                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value));
11788                         ins->type = STACK_MP;
11789                         *sp++ = ins;
11790                         ip += 5;
11791                         break;
11792                 }
11793                 case CEE_MKREFANY: {
11794                         MonoInst *loc, *addr;
11795
11796                         GSHAREDVT_FAILURE (*ip);
11797
11798                         CHECK_STACK (1);
11799                         MONO_INST_NEW (cfg, ins, *ip);
11800                         --sp;
11801                         CHECK_OPSIZE (5);
11802                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11803                         CHECK_TYPELOAD (klass);
11804
11805                         context_used = mini_class_check_context_used (cfg, klass);
11806
11807                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
11808                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
11809
11810                         if (context_used) {
11811                                 MonoInst *const_ins;
11812                                 int type_reg = alloc_preg (cfg);
11813
11814                                 const_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
11815                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
11816                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11817                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11818                         } else if (cfg->compile_aot) {
11819                                 int const_reg = alloc_preg (cfg);
11820                                 int type_reg = alloc_preg (cfg);
11821
11822                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
11823                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
11824                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11825                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11826                         } else {
11827                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), &klass->byval_arg);
11828                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), klass);
11829                         }
11830                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
11831
11832                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
11833                         ins->type = STACK_VTYPE;
11834                         ins->klass = mono_defaults.typed_reference_class;
11835                         *sp++ = ins;
11836                         ip += 5;
11837                         break;
11838                 }
11839                 case CEE_LDTOKEN: {
11840                         gpointer handle;
11841                         MonoClass *handle_class;
11842
11843                         CHECK_STACK_OVF (1);
11844
11845                         CHECK_OPSIZE (5);
11846                         n = read32 (ip + 1);
11847
11848                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
11849                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
11850                                 handle = mono_method_get_wrapper_data (method, n);
11851                                 handle_class = mono_method_get_wrapper_data (method, n + 1);
11852                                 if (handle_class == mono_defaults.typehandle_class)
11853                                         handle = &((MonoClass*)handle)->byval_arg;
11854                         }
11855                         else {
11856                                 handle = mono_ldtoken_checked (image, n, &handle_class, generic_context, &cfg->error);
11857                                 CHECK_CFG_ERROR;
11858                         }
11859                         if (!handle)
11860                                 LOAD_ERROR;
11861                         mono_class_init (handle_class);
11862                         if (cfg->generic_sharing_context) {
11863                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
11864                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
11865                                         /* This case handles ldtoken
11866                                            of an open type, like for
11867                                            typeof(Gen<>). */
11868                                         context_used = 0;
11869                                 } else if (handle_class == mono_defaults.typehandle_class) {
11870                                         context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type (handle));
11871                                 } else if (handle_class == mono_defaults.fieldhandle_class)
11872                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
11873                                 else if (handle_class == mono_defaults.methodhandle_class)
11874                                         context_used = mini_method_check_context_used (cfg, handle);
11875                                 else
11876                                         g_assert_not_reached ();
11877                         }
11878
11879                         if ((cfg->opt & MONO_OPT_SHARED) &&
11880                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
11881                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
11882                                 MonoInst *addr, *vtvar, *iargs [3];
11883                                 int method_context_used;
11884
11885                                 method_context_used = mini_method_check_context_used (cfg, method);
11886
11887                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
11888
11889                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
11890                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
11891                                 if (method_context_used) {
11892                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
11893                                                 method, MONO_RGCTX_INFO_METHOD);
11894                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
11895                                 } else {
11896                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
11897                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
11898                                 }
11899                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11900
11901                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11902
11903                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11904                         } else {
11905                                 if ((ip + 5 < end) && ip_in_bb (cfg, bblock, ip + 5) && 
11906                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
11907                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
11908                                         (cmethod->klass == mono_defaults.systemtype_class) &&
11909                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
11910                                         MonoClass *tclass = mono_class_from_mono_type (handle);
11911
11912                                         mono_class_init (tclass);
11913                                         if (context_used) {
11914                                                 ins = emit_get_rgctx_klass (cfg, context_used,
11915                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
11916                                         } else if (cfg->compile_aot) {
11917                                                 if (method->wrapper_type) {
11918                                                         mono_error_init (&error); //got to do it since there are multiple conditionals below
11919                                                         if (mono_class_get_checked (tclass->image, tclass->type_token, &error) == tclass && !generic_context) {
11920                                                                 /* Special case for static synchronized wrappers */
11921                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
11922                                                         } else {
11923                                                                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
11924                                                                 /* FIXME: n is not a normal token */
11925                                                                 DISABLE_AOT (cfg);
11926                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11927                                                         }
11928                                                 } else {
11929                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
11930                                                 }
11931                                         } else {
11932                                                 EMIT_NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
11933                                         }
11934                                         ins->type = STACK_OBJ;
11935                                         ins->klass = cmethod->klass;
11936                                         ip += 5;
11937                                 } else {
11938                                         MonoInst *addr, *vtvar;
11939
11940                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
11941
11942                                         if (context_used) {
11943                                                 if (handle_class == mono_defaults.typehandle_class) {
11944                                                         ins = emit_get_rgctx_klass (cfg, context_used,
11945                                                                         mono_class_from_mono_type (handle),
11946                                                                         MONO_RGCTX_INFO_TYPE);
11947                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
11948                                                         ins = emit_get_rgctx_method (cfg, context_used,
11949                                                                         handle, MONO_RGCTX_INFO_METHOD);
11950                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
11951                                                         ins = emit_get_rgctx_field (cfg, context_used,
11952                                                                         handle, MONO_RGCTX_INFO_CLASS_FIELD);
11953                                                 } else {
11954                                                         g_assert_not_reached ();
11955                                                 }
11956                                         } else if (cfg->compile_aot) {
11957                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
11958                                         } else {
11959                                                 EMIT_NEW_PCONST (cfg, ins, handle);
11960                                         }
11961                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11962                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11963                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11964                                 }
11965                         }
11966
11967                         *sp++ = ins;
11968                         ip += 5;
11969                         break;
11970                 }
11971                 case CEE_THROW:
11972                         CHECK_STACK (1);
11973                         MONO_INST_NEW (cfg, ins, OP_THROW);
11974                         --sp;
11975                         ins->sreg1 = sp [0]->dreg;
11976                         ip++;
11977                         bblock->out_of_line = TRUE;
11978                         MONO_ADD_INS (bblock, ins);
11979                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
11980                         MONO_ADD_INS (bblock, ins);
11981                         sp = stack_start;
11982                         
11983                         link_bblock (cfg, bblock, end_bblock);
11984                         start_new_bblock = 1;
11985                         break;
11986                 case CEE_ENDFINALLY:
11987                         /* mono_save_seq_point_info () depends on this */
11988                         if (sp != stack_start)
11989                                 emit_seq_point (cfg, method, ip, FALSE, FALSE);
11990                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
11991                         MONO_ADD_INS (bblock, ins);
11992                         ip++;
11993                         start_new_bblock = 1;
11994
11995                         /*
11996                          * Control will leave the method so empty the stack, otherwise
11997                          * the next basic block will start with a nonempty stack.
11998                          */
11999                         while (sp != stack_start) {
12000                                 sp--;
12001                         }
12002                         break;
12003                 case CEE_LEAVE:
12004                 case CEE_LEAVE_S: {
12005                         GList *handlers;
12006
12007                         if (*ip == CEE_LEAVE) {
12008                                 CHECK_OPSIZE (5);
12009                                 target = ip + 5 + (gint32)read32(ip + 1);
12010                         } else {
12011                                 CHECK_OPSIZE (2);
12012                                 target = ip + 2 + (signed char)(ip [1]);
12013                         }
12014
12015                         /* empty the stack */
12016                         while (sp != stack_start) {
12017                                 sp--;
12018                         }
12019
12020                         /* 
12021                          * If this leave statement is in a catch block, check for a
12022                          * pending exception, and rethrow it if necessary.
12023                          * We avoid doing this in runtime invoke wrappers, since those are called
12024                          * by native code which excepts the wrapper to catch all exceptions.
12025                          */
12026                         for (i = 0; i < header->num_clauses; ++i) {
12027                                 MonoExceptionClause *clause = &header->clauses [i];
12028
12029                                 /* 
12030                                  * Use <= in the final comparison to handle clauses with multiple
12031                                  * leave statements, like in bug #78024.
12032                                  * The ordering of the exception clauses guarantees that we find the
12033                                  * innermost clause.
12034                                  */
12035                                 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) {
12036                                         MonoInst *exc_ins;
12037                                         MonoBasicBlock *dont_throw;
12038
12039                                         /*
12040                                           MonoInst *load;
12041
12042                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
12043                                         */
12044
12045                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
12046
12047                                         NEW_BBLOCK (cfg, dont_throw);
12048
12049                                         /*
12050                                          * Currently, we always rethrow the abort exception, despite the 
12051                                          * fact that this is not correct. See thread6.cs for an example. 
12052                                          * But propagating the abort exception is more important than 
12053                                          * getting the sematics right.
12054                                          */
12055                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
12056                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
12057                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
12058
12059                                         MONO_START_BB (cfg, dont_throw);
12060                                         bblock = cfg->cbb;
12061                                 }
12062                         }
12063
12064                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
12065                                 GList *tmp;
12066                                 MonoExceptionClause *clause;
12067
12068                                 for (tmp = handlers; tmp; tmp = tmp->next) {
12069                                         clause = tmp->data;
12070                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
12071                                         g_assert (tblock);
12072                                         link_bblock (cfg, bblock, tblock);
12073                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
12074                                         ins->inst_target_bb = tblock;
12075                                         ins->inst_eh_block = clause;
12076                                         MONO_ADD_INS (bblock, ins);
12077                                         bblock->has_call_handler = 1;
12078                                         if (COMPILE_LLVM (cfg)) {
12079                                                 MonoBasicBlock *target_bb;
12080
12081                                                 /* 
12082                                                  * Link the finally bblock with the target, since it will
12083                                                  * conceptually branch there.
12084                                                  * FIXME: Have to link the bblock containing the endfinally.
12085                                                  */
12086                                                 GET_BBLOCK (cfg, target_bb, target);
12087                                                 link_bblock (cfg, tblock, target_bb);
12088                                         }
12089                                 }
12090                                 g_list_free (handlers);
12091                         } 
12092
12093                         MONO_INST_NEW (cfg, ins, OP_BR);
12094                         MONO_ADD_INS (bblock, ins);
12095                         GET_BBLOCK (cfg, tblock, target);
12096                         link_bblock (cfg, bblock, tblock);
12097                         ins->inst_target_bb = tblock;
12098                         start_new_bblock = 1;
12099
12100                         if (*ip == CEE_LEAVE)
12101                                 ip += 5;
12102                         else
12103                                 ip += 2;
12104
12105                         break;
12106                 }
12107
12108                         /*
12109                          * Mono specific opcodes
12110                          */
12111                 case MONO_CUSTOM_PREFIX: {
12112
12113                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
12114
12115                         CHECK_OPSIZE (2);
12116                         switch (ip [1]) {
12117                         case CEE_MONO_ICALL: {
12118                                 gpointer func;
12119                                 MonoJitICallInfo *info;
12120
12121                                 token = read32 (ip + 2);
12122                                 func = mono_method_get_wrapper_data (method, token);
12123                                 info = mono_find_jit_icall_by_addr (func);
12124                                 if (!info)
12125                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
12126                                 g_assert (info);
12127
12128                                 CHECK_STACK (info->sig->param_count);
12129                                 sp -= info->sig->param_count;
12130
12131                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
12132                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
12133                                         *sp++ = ins;
12134
12135                                 ip += 6;
12136                                 inline_costs += 10 * num_calls++;
12137
12138                                 break;
12139                         }
12140                         case CEE_MONO_LDPTR_CARD_TABLE: {
12141                                 int shift_bits;
12142                                 gpointer card_mask;
12143                                 CHECK_STACK_OVF (1);
12144
12145                                 if (cfg->compile_aot)
12146                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
12147                                 else
12148                                         EMIT_NEW_PCONST (cfg, ins, mono_gc_get_card_table (&shift_bits, &card_mask));
12149
12150                                 *sp++ = ins;
12151                                 ip += 2;
12152                                 inline_costs += 10 * num_calls++;
12153                                 break;
12154                         }
12155                         case CEE_MONO_LDPTR_NURSERY_START: {
12156                                 int shift_bits;
12157                                 size_t size;
12158                                 CHECK_STACK_OVF (1);
12159
12160                                 if (cfg->compile_aot)
12161                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_GC_NURSERY_START, NULL);
12162                                 else
12163                                         EMIT_NEW_PCONST (cfg, ins, mono_gc_get_nursery (&shift_bits, &size));
12164
12165                                 *sp++ = ins;
12166                                 ip += 2;
12167                                 inline_costs += 10 * num_calls++;
12168                                 break;
12169                         }
12170                         case CEE_MONO_LDPTR_INT_REQ_FLAG: {
12171                                 CHECK_STACK_OVF (1);
12172
12173                                 if (cfg->compile_aot)
12174                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
12175                                 else
12176                                         EMIT_NEW_PCONST (cfg, ins, mono_thread_interruption_request_flag ());
12177
12178                                 *sp++ = ins;
12179                                 ip += 2;
12180                                 inline_costs += 10 * num_calls++;
12181                                 break;
12182                         }
12183                         case CEE_MONO_LDPTR: {
12184                                 gpointer ptr;
12185
12186                                 CHECK_STACK_OVF (1);
12187                                 CHECK_OPSIZE (6);
12188                                 token = read32 (ip + 2);
12189
12190                                 ptr = mono_method_get_wrapper_data (method, token);
12191                                 EMIT_NEW_PCONST (cfg, ins, ptr);
12192                                 *sp++ = ins;
12193                                 ip += 6;
12194                                 inline_costs += 10 * num_calls++;
12195                                 /* Can't embed random pointers into AOT code */
12196                                 DISABLE_AOT (cfg);
12197                                 break;
12198                         }
12199                         case CEE_MONO_JIT_ICALL_ADDR: {
12200                                 MonoJitICallInfo *callinfo;
12201                                 gpointer ptr;
12202
12203                                 CHECK_STACK_OVF (1);
12204                                 CHECK_OPSIZE (6);
12205                                 token = read32 (ip + 2);
12206
12207                                 ptr = mono_method_get_wrapper_data (method, token);
12208                                 callinfo = mono_find_jit_icall_by_addr (ptr);
12209                                 g_assert (callinfo);
12210                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
12211                                 *sp++ = ins;
12212                                 ip += 6;
12213                                 inline_costs += 10 * num_calls++;
12214                                 break;
12215                         }
12216                         case CEE_MONO_ICALL_ADDR: {
12217                                 MonoMethod *cmethod;
12218                                 gpointer ptr;
12219
12220                                 CHECK_STACK_OVF (1);
12221                                 CHECK_OPSIZE (6);
12222                                 token = read32 (ip + 2);
12223
12224                                 cmethod = mono_method_get_wrapper_data (method, token);
12225
12226                                 if (cfg->compile_aot) {
12227                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
12228                                 } else {
12229                                         ptr = mono_lookup_internal_call (cmethod);
12230                                         g_assert (ptr);
12231                                         EMIT_NEW_PCONST (cfg, ins, ptr);
12232                                 }
12233                                 *sp++ = ins;
12234                                 ip += 6;
12235                                 break;
12236                         }
12237                         case CEE_MONO_VTADDR: {
12238                                 MonoInst *src_var, *src;
12239
12240                                 CHECK_STACK (1);
12241                                 --sp;
12242
12243                                 // FIXME:
12244                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12245                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
12246                                 *sp++ = src;
12247                                 ip += 2;
12248                                 break;
12249                         }
12250                         case CEE_MONO_NEWOBJ: {
12251                                 MonoInst *iargs [2];
12252
12253                                 CHECK_STACK_OVF (1);
12254                                 CHECK_OPSIZE (6);
12255                                 token = read32 (ip + 2);
12256                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12257                                 mono_class_init (klass);
12258                                 NEW_DOMAINCONST (cfg, iargs [0]);
12259                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
12260                                 NEW_CLASSCONST (cfg, iargs [1], klass);
12261                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
12262                                 *sp++ = mono_emit_jit_icall (cfg, mono_object_new, iargs);
12263                                 ip += 6;
12264                                 inline_costs += 10 * num_calls++;
12265                                 break;
12266                         }
12267                         case CEE_MONO_OBJADDR:
12268                                 CHECK_STACK (1);
12269                                 --sp;
12270                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
12271                                 ins->dreg = alloc_ireg_mp (cfg);
12272                                 ins->sreg1 = sp [0]->dreg;
12273                                 ins->type = STACK_MP;
12274                                 MONO_ADD_INS (cfg->cbb, ins);
12275                                 *sp++ = ins;
12276                                 ip += 2;
12277                                 break;
12278                         case CEE_MONO_LDNATIVEOBJ:
12279                                 /*
12280                                  * Similar to LDOBJ, but instead load the unmanaged 
12281                                  * representation of the vtype to the stack.
12282                                  */
12283                                 CHECK_STACK (1);
12284                                 CHECK_OPSIZE (6);
12285                                 --sp;
12286                                 token = read32 (ip + 2);
12287                                 klass = mono_method_get_wrapper_data (method, token);
12288                                 g_assert (klass->valuetype);
12289                                 mono_class_init (klass);
12290
12291                                 {
12292                                         MonoInst *src, *dest, *temp;
12293
12294                                         src = sp [0];
12295                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
12296                                         temp->backend.is_pinvoke = 1;
12297                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
12298                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
12299
12300                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
12301                                         dest->type = STACK_VTYPE;
12302                                         dest->klass = klass;
12303
12304                                         *sp ++ = dest;
12305                                         ip += 6;
12306                                 }
12307                                 break;
12308                         case CEE_MONO_RETOBJ: {
12309                                 /*
12310                                  * Same as RET, but return the native representation of a vtype
12311                                  * to the caller.
12312                                  */
12313                                 g_assert (cfg->ret);
12314                                 g_assert (mono_method_signature (method)->pinvoke); 
12315                                 CHECK_STACK (1);
12316                                 --sp;
12317                                 
12318                                 CHECK_OPSIZE (6);
12319                                 token = read32 (ip + 2);    
12320                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12321
12322                                 if (!cfg->vret_addr) {
12323                                         g_assert (cfg->ret_var_is_local);
12324
12325                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
12326                                 } else {
12327                                         EMIT_NEW_RETLOADA (cfg, ins);
12328                                 }
12329                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
12330                                 
12331                                 if (sp != stack_start)
12332                                         UNVERIFIED;
12333                                 
12334                                 MONO_INST_NEW (cfg, ins, OP_BR);
12335                                 ins->inst_target_bb = end_bblock;
12336                                 MONO_ADD_INS (bblock, ins);
12337                                 link_bblock (cfg, bblock, end_bblock);
12338                                 start_new_bblock = 1;
12339                                 ip += 6;
12340                                 break;
12341                         }
12342                         case CEE_MONO_CISINST:
12343                         case CEE_MONO_CCASTCLASS: {
12344                                 int token;
12345                                 CHECK_STACK (1);
12346                                 --sp;
12347                                 CHECK_OPSIZE (6);
12348                                 token = read32 (ip + 2);
12349                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12350                                 if (ip [1] == CEE_MONO_CISINST)
12351                                         ins = handle_cisinst (cfg, klass, sp [0]);
12352                                 else
12353                                         ins = handle_ccastclass (cfg, klass, sp [0]);
12354                                 bblock = cfg->cbb;
12355                                 *sp++ = ins;
12356                                 ip += 6;
12357                                 break;
12358                         }
12359                         case CEE_MONO_SAVE_LMF:
12360                         case CEE_MONO_RESTORE_LMF:
12361 #ifdef MONO_ARCH_HAVE_LMF_OPS
12362                                 MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_SAVE_LMF) ? OP_SAVE_LMF : OP_RESTORE_LMF);
12363                                 MONO_ADD_INS (bblock, ins);
12364                                 cfg->need_lmf_area = TRUE;
12365 #endif
12366                                 ip += 2;
12367                                 break;
12368                         case CEE_MONO_CLASSCONST:
12369                                 CHECK_STACK_OVF (1);
12370                                 CHECK_OPSIZE (6);
12371                                 token = read32 (ip + 2);
12372                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
12373                                 *sp++ = ins;
12374                                 ip += 6;
12375                                 inline_costs += 10 * num_calls++;
12376                                 break;
12377                         case CEE_MONO_NOT_TAKEN:
12378                                 bblock->out_of_line = TRUE;
12379                                 ip += 2;
12380                                 break;
12381                         case CEE_MONO_TLS: {
12382                                 int key;
12383
12384                                 CHECK_STACK_OVF (1);
12385                                 CHECK_OPSIZE (6);
12386                                 key = (gint32)read32 (ip + 2);
12387                                 g_assert (key < TLS_KEY_NUM);
12388
12389                                 ins = mono_create_tls_get (cfg, key);
12390                                 if (!ins) {
12391                                         if (cfg->compile_aot) {
12392                                                 DISABLE_AOT (cfg);
12393                                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
12394                                                 ins->dreg = alloc_preg (cfg);
12395                                                 ins->type = STACK_PTR;
12396                                         } else {
12397                                                 g_assert_not_reached ();
12398                                         }
12399                                 }
12400                                 ins->type = STACK_PTR;
12401                                 MONO_ADD_INS (bblock, ins);
12402                                 *sp++ = ins;
12403                                 ip += 6;
12404                                 break;
12405                         }
12406                         case CEE_MONO_DYN_CALL: {
12407                                 MonoCallInst *call;
12408
12409                                 /* It would be easier to call a trampoline, but that would put an
12410                                  * extra frame on the stack, confusing exception handling. So
12411                                  * implement it inline using an opcode for now.
12412                                  */
12413
12414                                 if (!cfg->dyn_call_var) {
12415                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12416                                         /* prevent it from being register allocated */
12417                                         cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
12418                                 }
12419
12420                                 /* Has to use a call inst since it local regalloc expects it */
12421                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
12422                                 ins = (MonoInst*)call;
12423                                 sp -= 2;
12424                                 ins->sreg1 = sp [0]->dreg;
12425                                 ins->sreg2 = sp [1]->dreg;
12426                                 MONO_ADD_INS (bblock, ins);
12427
12428                                 cfg->param_area = MAX (cfg->param_area, MONO_ARCH_DYN_CALL_PARAM_AREA);
12429
12430                                 ip += 2;
12431                                 inline_costs += 10 * num_calls++;
12432
12433                                 break;
12434                         }
12435                         case CEE_MONO_MEMORY_BARRIER: {
12436                                 CHECK_OPSIZE (6);
12437                                 emit_memory_barrier (cfg, (int)read32 (ip + 2));
12438                                 ip += 6;
12439                                 break;
12440                         }
12441                         case CEE_MONO_JIT_ATTACH: {
12442                                 MonoInst *args [16], *domain_ins;
12443                                 MonoInst *ad_ins, *jit_tls_ins;
12444                                 MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
12445
12446                                 cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12447
12448                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12449                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12450
12451                                 ad_ins = mono_get_domain_intrinsic (cfg);
12452                                 jit_tls_ins = mono_get_jit_tls_intrinsic (cfg);
12453
12454                                 if (MONO_ARCH_HAVE_TLS_GET && ad_ins && jit_tls_ins) {
12455                                         NEW_BBLOCK (cfg, next_bb);
12456                                         NEW_BBLOCK (cfg, call_bb);
12457
12458                                         if (cfg->compile_aot) {
12459                                                 /* AOT code is only used in the root domain */
12460                                                 EMIT_NEW_PCONST (cfg, domain_ins, NULL);
12461                                         } else {
12462                                                 EMIT_NEW_PCONST (cfg, domain_ins, cfg->domain);
12463                                         }
12464                                         MONO_ADD_INS (cfg->cbb, ad_ins);
12465                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg);
12466                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb);
12467
12468                                         MONO_ADD_INS (cfg->cbb, jit_tls_ins);
12469                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0);
12470                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb);
12471
12472                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb);
12473                                         MONO_START_BB (cfg, call_bb);
12474                                 }
12475
12476                                 if (cfg->compile_aot) {
12477                                         /* AOT code is only used in the root domain */
12478                                         EMIT_NEW_PCONST (cfg, args [0], NULL);
12479                                 } else {
12480                                         EMIT_NEW_PCONST (cfg, args [0], cfg->domain);
12481                                 }
12482                                 ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
12483                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12484
12485                                 if (next_bb) {
12486                                         MONO_START_BB (cfg, next_bb);
12487                                         bblock = cfg->cbb;
12488                                 }
12489                                 ip += 2;
12490                                 break;
12491                         }
12492                         case CEE_MONO_JIT_DETACH: {
12493                                 MonoInst *args [16];
12494
12495                                 /* Restore the original domain */
12496                                 dreg = alloc_ireg (cfg);
12497                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->orig_domain_var->dreg);
12498                                 mono_emit_jit_icall (cfg, mono_jit_set_domain, args);
12499                                 ip += 2;
12500                                 break;
12501                         }
12502                         default:
12503                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
12504                                 break;
12505                         }
12506                         break;
12507                 }
12508
12509                 case CEE_PREFIX1: {
12510                         CHECK_OPSIZE (2);
12511                         switch (ip [1]) {
12512                         case CEE_ARGLIST: {
12513                                 /* somewhat similar to LDTOKEN */
12514                                 MonoInst *addr, *vtvar;
12515                                 CHECK_STACK_OVF (1);
12516                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
12517
12518                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12519                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
12520
12521                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12522                                 ins->type = STACK_VTYPE;
12523                                 ins->klass = mono_defaults.argumenthandle_class;
12524                                 *sp++ = ins;
12525                                 ip += 2;
12526                                 break;
12527                         }
12528                         case CEE_CEQ:
12529                         case CEE_CGT:
12530                         case CEE_CGT_UN:
12531                         case CEE_CLT:
12532                         case CEE_CLT_UN: {
12533                                 MonoInst *cmp, *arg1, *arg2;
12534
12535                                 CHECK_STACK (2);
12536                                 sp -= 2;
12537                                 arg1 = sp [0];
12538                                 arg2 = sp [1];
12539
12540                                 /*
12541                                  * The following transforms:
12542                                  *    CEE_CEQ    into OP_CEQ
12543                                  *    CEE_CGT    into OP_CGT
12544                                  *    CEE_CGT_UN into OP_CGT_UN
12545                                  *    CEE_CLT    into OP_CLT
12546                                  *    CEE_CLT_UN into OP_CLT_UN
12547                                  */
12548                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
12549
12550                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
12551                                 cmp->sreg1 = arg1->dreg;
12552                                 cmp->sreg2 = arg2->dreg;
12553                                 type_from_op (cfg, cmp, arg1, arg2);
12554                                 CHECK_TYPE (cmp);
12555                                 add_widen_op (cfg, cmp, &arg1, &arg2);
12556                                 if ((arg1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((arg1->type == STACK_PTR) || (arg1->type == STACK_OBJ) || (arg1->type == STACK_MP))))
12557                                         cmp->opcode = OP_LCOMPARE;
12558                                 else if (arg1->type == STACK_R4)
12559                                         cmp->opcode = OP_RCOMPARE;
12560                                 else if (arg1->type == STACK_R8)
12561                                         cmp->opcode = OP_FCOMPARE;
12562                                 else
12563                                         cmp->opcode = OP_ICOMPARE;
12564                                 MONO_ADD_INS (bblock, cmp);
12565                                 ins->type = STACK_I4;
12566                                 ins->dreg = alloc_dreg (cfg, ins->type);
12567                                 type_from_op (cfg, ins, arg1, arg2);
12568
12569                                 if (cmp->opcode == OP_FCOMPARE || cmp->opcode == OP_RCOMPARE) {
12570                                         /*
12571                                          * The backends expect the fceq opcodes to do the
12572                                          * comparison too.
12573                                          */
12574                                         ins->sreg1 = cmp->sreg1;
12575                                         ins->sreg2 = cmp->sreg2;
12576                                         NULLIFY_INS (cmp);
12577                                 }
12578                                 MONO_ADD_INS (bblock, ins);
12579                                 *sp++ = ins;
12580                                 ip += 2;
12581                                 break;
12582                         }
12583                         case CEE_LDFTN: {
12584                                 MonoInst *argconst;
12585                                 MonoMethod *cil_method;
12586
12587                                 CHECK_STACK_OVF (1);
12588                                 CHECK_OPSIZE (6);
12589                                 n = read32 (ip + 2);
12590                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12591                                 if (!cmethod || mono_loader_get_last_error ())
12592                                         LOAD_ERROR;
12593                                 mono_class_init (cmethod->klass);
12594
12595                                 mono_save_token_info (cfg, image, n, cmethod);
12596
12597                                 context_used = mini_method_check_context_used (cfg, cmethod);
12598
12599                                 cil_method = cmethod;
12600                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
12601                                         METHOD_ACCESS_FAILURE (method, cil_method);
12602
12603                                 if (mono_security_cas_enabled ()) {
12604                                         if (check_linkdemand (cfg, method, cmethod))
12605                                                 INLINE_FAILURE ("linkdemand");
12606                                         CHECK_CFG_EXCEPTION;
12607                                 } else if (mono_security_core_clr_enabled ()) {
12608                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
12609                                 }
12610
12611                                 /* 
12612                                  * Optimize the common case of ldftn+delegate creation
12613                                  */
12614                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, bblock, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
12615                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12616                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12617                                                 MonoInst *target_ins, *handle_ins;
12618                                                 MonoMethod *invoke;
12619                                                 int invoke_context_used;
12620
12621                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12622                                                 if (!invoke || !mono_method_signature (invoke))
12623                                                         LOAD_ERROR;
12624
12625                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12626
12627                                                 target_ins = sp [-1];
12628
12629                                                 if (mono_security_core_clr_enabled ())
12630                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method, bblock, ip);
12631
12632                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
12633                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
12634                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
12635                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
12636                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
12637                                                         }
12638                                                 }
12639
12640 #if defined(MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE)
12641                                                 /* FIXME: SGEN support */
12642                                                 if (invoke_context_used == 0) {
12643                                                         ip += 6;
12644                                                         if (cfg->verbose_level > 3)
12645                                                                 g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
12646                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, FALSE))) {
12647                                                                 sp --;
12648                                                                 *sp = handle_ins;
12649                                                                 CHECK_CFG_EXCEPTION;
12650                                                                 ip += 5;
12651                                                                 sp ++;
12652                                                                 break;
12653                                                         }
12654                                                         ip -= 6;
12655                                                 }
12656 #endif
12657                                         }
12658                                 }
12659
12660                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
12661                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
12662                                 *sp++ = ins;
12663                                 
12664                                 ip += 6;
12665                                 inline_costs += 10 * num_calls++;
12666                                 break;
12667                         }
12668                         case CEE_LDVIRTFTN: {
12669                                 MonoInst *args [2];
12670
12671                                 CHECK_STACK (1);
12672                                 CHECK_OPSIZE (6);
12673                                 n = read32 (ip + 2);
12674                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12675                                 if (!cmethod || mono_loader_get_last_error ())
12676                                         LOAD_ERROR;
12677                                 mono_class_init (cmethod->klass);
12678  
12679                                 context_used = mini_method_check_context_used (cfg, cmethod);
12680
12681                                 if (mono_security_cas_enabled ()) {
12682                                         if (check_linkdemand (cfg, method, cmethod))
12683                                                 INLINE_FAILURE ("linkdemand");
12684                                         CHECK_CFG_EXCEPTION;
12685                                 } else if (mono_security_core_clr_enabled ()) {
12686                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
12687                                 }
12688
12689                                 /*
12690                                  * Optimize the common case of ldvirtftn+delegate creation
12691                                  */
12692                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, bblock, ip + 6) && (ip [6] == CEE_NEWOBJ) && (ip > header->code && ip [-1] == CEE_DUP)) {
12693                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12694                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12695                                                 MonoInst *target_ins, *handle_ins;
12696                                                 MonoMethod *invoke;
12697                                                 int invoke_context_used;
12698
12699                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12700                                                 if (!invoke || !mono_method_signature (invoke))
12701                                                         LOAD_ERROR;
12702
12703                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12704
12705                                                 target_ins = sp [-1];
12706
12707                                                 if (mono_security_core_clr_enabled ())
12708                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method, bblock, ip);
12709
12710 #if defined(MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE)
12711                                                 /* FIXME: SGEN support */
12712                                                 if (invoke_context_used == 0) {
12713                                                         ip += 6;
12714                                                         if (cfg->verbose_level > 3)
12715                                                                 g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
12716                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, TRUE))) {
12717                                                                 sp -= 2;
12718                                                                 *sp = handle_ins;
12719                                                                 CHECK_CFG_EXCEPTION;
12720                                                                 ip += 5;
12721                                                                 sp ++;
12722                                                                 break;
12723                                                         }
12724                                                         ip -= 6;
12725                                                 }
12726 #endif
12727                                         }
12728                                 }
12729
12730                                 --sp;
12731                                 args [0] = *sp;
12732
12733                                 args [1] = emit_get_rgctx_method (cfg, context_used,
12734                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
12735
12736                                 if (context_used)
12737                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
12738                                 else
12739                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
12740
12741                                 ip += 6;
12742                                 inline_costs += 10 * num_calls++;
12743                                 break;
12744                         }
12745                         case CEE_LDARG:
12746                                 CHECK_STACK_OVF (1);
12747                                 CHECK_OPSIZE (4);
12748                                 n = read16 (ip + 2);
12749                                 CHECK_ARG (n);
12750                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
12751                                 *sp++ = ins;
12752                                 ip += 4;
12753                                 break;
12754                         case CEE_LDARGA:
12755                                 CHECK_STACK_OVF (1);
12756                                 CHECK_OPSIZE (4);
12757                                 n = read16 (ip + 2);
12758                                 CHECK_ARG (n);
12759                                 NEW_ARGLOADA (cfg, ins, n);
12760                                 MONO_ADD_INS (cfg->cbb, ins);
12761                                 *sp++ = ins;
12762                                 ip += 4;
12763                                 break;
12764                         case CEE_STARG:
12765                                 CHECK_STACK (1);
12766                                 --sp;
12767                                 CHECK_OPSIZE (4);
12768                                 n = read16 (ip + 2);
12769                                 CHECK_ARG (n);
12770                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
12771                                         UNVERIFIED;
12772                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
12773                                 ip += 4;
12774                                 break;
12775                         case CEE_LDLOC:
12776                                 CHECK_STACK_OVF (1);
12777                                 CHECK_OPSIZE (4);
12778                                 n = read16 (ip + 2);
12779                                 CHECK_LOCAL (n);
12780                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
12781                                 *sp++ = ins;
12782                                 ip += 4;
12783                                 break;
12784                         case CEE_LDLOCA: {
12785                                 unsigned char *tmp_ip;
12786                                 CHECK_STACK_OVF (1);
12787                                 CHECK_OPSIZE (4);
12788                                 n = read16 (ip + 2);
12789                                 CHECK_LOCAL (n);
12790
12791                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
12792                                         ip = tmp_ip;
12793                                         inline_costs += 1;
12794                                         break;
12795                                 }                       
12796                                 
12797                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
12798                                 *sp++ = ins;
12799                                 ip += 4;
12800                                 break;
12801                         }
12802                         case CEE_STLOC:
12803                                 CHECK_STACK (1);
12804                                 --sp;
12805                                 CHECK_OPSIZE (4);
12806                                 n = read16 (ip + 2);
12807                                 CHECK_LOCAL (n);
12808                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
12809                                         UNVERIFIED;
12810                                 emit_stloc_ir (cfg, sp, header, n);
12811                                 ip += 4;
12812                                 inline_costs += 1;
12813                                 break;
12814                         case CEE_LOCALLOC:
12815                                 CHECK_STACK (1);
12816                                 --sp;
12817                                 if (sp != stack_start) 
12818                                         UNVERIFIED;
12819                                 if (cfg->method != method) 
12820                                         /* 
12821                                          * Inlining this into a loop in a parent could lead to 
12822                                          * stack overflows which is different behavior than the
12823                                          * non-inlined case, thus disable inlining in this case.
12824                                          */
12825                                         INLINE_FAILURE("localloc");
12826
12827                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
12828                                 ins->dreg = alloc_preg (cfg);
12829                                 ins->sreg1 = sp [0]->dreg;
12830                                 ins->type = STACK_PTR;
12831                                 MONO_ADD_INS (cfg->cbb, ins);
12832
12833                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12834                                 if (init_locals)
12835                                         ins->flags |= MONO_INST_INIT;
12836
12837                                 *sp++ = ins;
12838                                 ip += 2;
12839                                 break;
12840                         case CEE_ENDFILTER: {
12841                                 MonoExceptionClause *clause, *nearest;
12842                                 int cc;
12843
12844                                 CHECK_STACK (1);
12845                                 --sp;
12846                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
12847                                         UNVERIFIED;
12848                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
12849                                 ins->sreg1 = (*sp)->dreg;
12850                                 MONO_ADD_INS (bblock, ins);
12851                                 start_new_bblock = 1;
12852                                 ip += 2;
12853
12854                                 nearest = NULL;
12855                                 for (cc = 0; cc < header->num_clauses; ++cc) {
12856                                         clause = &header->clauses [cc];
12857                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
12858                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
12859                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset)))
12860                                                 nearest = clause;
12861                                 }
12862                                 g_assert (nearest);
12863                                 if ((ip - header->code) != nearest->handler_offset)
12864                                         UNVERIFIED;
12865
12866                                 break;
12867                         }
12868                         case CEE_UNALIGNED_:
12869                                 ins_flag |= MONO_INST_UNALIGNED;
12870                                 /* FIXME: record alignment? we can assume 1 for now */
12871                                 CHECK_OPSIZE (3);
12872                                 ip += 3;
12873                                 break;
12874                         case CEE_VOLATILE_:
12875                                 ins_flag |= MONO_INST_VOLATILE;
12876                                 ip += 2;
12877                                 break;
12878                         case CEE_TAIL_:
12879                                 ins_flag   |= MONO_INST_TAILCALL;
12880                                 cfg->flags |= MONO_CFG_HAS_TAIL;
12881                                 /* Can't inline tail calls at this time */
12882                                 inline_costs += 100000;
12883                                 ip += 2;
12884                                 break;
12885                         case CEE_INITOBJ:
12886                                 CHECK_STACK (1);
12887                                 --sp;
12888                                 CHECK_OPSIZE (6);
12889                                 token = read32 (ip + 2);
12890                                 klass = mini_get_class (method, token, generic_context);
12891                                 CHECK_TYPELOAD (klass);
12892                                 if (generic_class_is_reference_type (cfg, klass))
12893                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
12894                                 else
12895                                         mini_emit_initobj (cfg, *sp, NULL, klass);
12896                                 ip += 6;
12897                                 inline_costs += 1;
12898                                 break;
12899                         case CEE_CONSTRAINED_:
12900                                 CHECK_OPSIZE (6);
12901                                 token = read32 (ip + 2);
12902                                 constrained_class = mini_get_class (method, token, generic_context);
12903                                 CHECK_TYPELOAD (constrained_class);
12904                                 ip += 6;
12905                                 break;
12906                         case CEE_CPBLK:
12907                         case CEE_INITBLK: {
12908                                 MonoInst *iargs [3];
12909                                 CHECK_STACK (3);
12910                                 sp -= 3;
12911
12912                                 /* Skip optimized paths for volatile operations. */
12913                                 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)) {
12914                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
12915                                 } 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)) {
12916                                         /* emit_memset only works when val == 0 */
12917                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
12918                                 } else {
12919                                         MonoInst *call;
12920                                         iargs [0] = sp [0];
12921                                         iargs [1] = sp [1];
12922                                         iargs [2] = sp [2];
12923                                         if (ip [1] == CEE_CPBLK) {
12924                                                 /*
12925                                                  * FIXME: It's unclear whether we should be emitting both the acquire
12926                                                  * and release barriers for cpblk. It is technically both a load and
12927                                                  * store operation, so it seems like that's the sensible thing to do.
12928                                                  *
12929                                                  * FIXME: We emit full barriers on both sides of the operation for
12930                                                  * simplicity. We should have a separate atomic memcpy method instead.
12931                                                  */
12932                                                 MonoMethod *memcpy_method = get_memcpy_method ();
12933
12934                                                 if (ins_flag & MONO_INST_VOLATILE)
12935                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12936
12937                                                 call = mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
12938                                                 call->flags |= ins_flag;
12939
12940                                                 if (ins_flag & MONO_INST_VOLATILE)
12941                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12942                                         } else {
12943                                                 MonoMethod *memset_method = get_memset_method ();
12944                                                 if (ins_flag & MONO_INST_VOLATILE) {
12945                                                         /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
12946                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
12947                                                 }
12948                                                 call = mono_emit_method_call (cfg, memset_method, iargs, NULL);
12949                                                 call->flags |= ins_flag;
12950                                         }
12951                                 }
12952                                 ip += 2;
12953                                 ins_flag = 0;
12954                                 inline_costs += 1;
12955                                 break;
12956                         }
12957                         case CEE_NO_:
12958                                 CHECK_OPSIZE (3);
12959                                 if (ip [2] & 0x1)
12960                                         ins_flag |= MONO_INST_NOTYPECHECK;
12961                                 if (ip [2] & 0x2)
12962                                         ins_flag |= MONO_INST_NORANGECHECK;
12963                                 /* we ignore the no-nullcheck for now since we
12964                                  * really do it explicitly only when doing callvirt->call
12965                                  */
12966                                 ip += 3;
12967                                 break;
12968                         case CEE_RETHROW: {
12969                                 MonoInst *load;
12970                                 int handler_offset = -1;
12971
12972                                 for (i = 0; i < header->num_clauses; ++i) {
12973                                         MonoExceptionClause *clause = &header->clauses [i];
12974                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
12975                                                 handler_offset = clause->handler_offset;
12976                                                 break;
12977                                         }
12978                                 }
12979
12980                                 bblock->flags |= BB_EXCEPTION_UNSAFE;
12981
12982                                 if (handler_offset == -1)
12983                                         UNVERIFIED;
12984
12985                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
12986                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
12987                                 ins->sreg1 = load->dreg;
12988                                 MONO_ADD_INS (bblock, ins);
12989
12990                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
12991                                 MONO_ADD_INS (bblock, ins);
12992
12993                                 sp = stack_start;
12994                                 link_bblock (cfg, bblock, end_bblock);
12995                                 start_new_bblock = 1;
12996                                 ip += 2;
12997                                 break;
12998                         }
12999                         case CEE_SIZEOF: {
13000                                 guint32 val;
13001                                 int ialign;
13002
13003                                 CHECK_STACK_OVF (1);
13004                                 CHECK_OPSIZE (6);
13005                                 token = read32 (ip + 2);
13006                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !image_is_dynamic (method->klass->image) && !generic_context) {
13007                                         MonoType *type = mono_type_create_from_typespec_checked (image, token, &cfg->error);
13008                                         CHECK_CFG_ERROR;
13009
13010                                         val = mono_type_size (type, &ialign);
13011                                 } else {
13012                                         MonoClass *klass = mini_get_class (method, token, generic_context);
13013                                         CHECK_TYPELOAD (klass);
13014
13015                                         val = mono_type_size (&klass->byval_arg, &ialign);
13016
13017                                         if (mini_is_gsharedvt_klass (cfg, klass))
13018                                                 GSHAREDVT_FAILURE (*ip);
13019                                 }
13020                                 EMIT_NEW_ICONST (cfg, ins, val);
13021                                 *sp++= ins;
13022                                 ip += 6;
13023                                 break;
13024                         }
13025                         case CEE_REFANYTYPE: {
13026                                 MonoInst *src_var, *src;
13027
13028                                 GSHAREDVT_FAILURE (*ip);
13029
13030                                 CHECK_STACK (1);
13031                                 --sp;
13032
13033                                 // FIXME:
13034                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
13035                                 if (!src_var)
13036                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
13037                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
13038                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type));
13039                                 *sp++ = ins;
13040                                 ip += 2;
13041                                 break;
13042                         }
13043                         case CEE_READONLY_:
13044                                 readonly = TRUE;
13045                                 ip += 2;
13046                                 break;
13047
13048                         case CEE_UNUSED56:
13049                         case CEE_UNUSED57:
13050                         case CEE_UNUSED70:
13051                         case CEE_UNUSED:
13052                         case CEE_UNUSED99:
13053                                 UNVERIFIED;
13054                                 
13055                         default:
13056                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
13057                                 UNVERIFIED;
13058                         }
13059                         break;
13060                 }
13061                 case CEE_UNUSED58:
13062                 case CEE_UNUSED1:
13063                         UNVERIFIED;
13064
13065                 default:
13066                         g_warning ("opcode 0x%02x not handled", *ip);
13067                         UNVERIFIED;
13068                 }
13069         }
13070         if (start_new_bblock != 1)
13071                 UNVERIFIED;
13072
13073         bblock->cil_length = ip - bblock->cil_code;
13074         if (bblock->next_bb) {
13075                 /* This could already be set because of inlining, #693905 */
13076                 MonoBasicBlock *bb = bblock;
13077
13078                 while (bb->next_bb)
13079                         bb = bb->next_bb;
13080                 bb->next_bb = end_bblock;
13081         } else {
13082                 bblock->next_bb = end_bblock;
13083         }
13084
13085         if (cfg->method == method && cfg->domainvar) {
13086                 MonoInst *store;
13087                 MonoInst *get_domain;
13088
13089                 cfg->cbb = init_localsbb;
13090
13091                 if ((get_domain = mono_get_domain_intrinsic (cfg))) {
13092                         MONO_ADD_INS (cfg->cbb, get_domain);
13093                 } else {
13094                         get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
13095                 }
13096                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
13097                 MONO_ADD_INS (cfg->cbb, store);
13098         }
13099
13100 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
13101         if (cfg->compile_aot)
13102                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
13103                 mono_get_got_var (cfg);
13104 #endif
13105
13106         if (cfg->method == method && cfg->got_var)
13107                 mono_emit_load_got_addr (cfg);
13108
13109         if (init_localsbb) {
13110                 cfg->cbb = init_localsbb;
13111                 cfg->ip = NULL;
13112                 for (i = 0; i < header->num_locals; ++i) {
13113                         emit_init_local (cfg, i, header->locals [i], init_locals);
13114                 }
13115         }
13116
13117         if (cfg->init_ref_vars && cfg->method == method) {
13118                 /* Emit initialization for ref vars */
13119                 // FIXME: Avoid duplication initialization for IL locals.
13120                 for (i = 0; i < cfg->num_varinfo; ++i) {
13121                         MonoInst *ins = cfg->varinfo [i];
13122
13123                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
13124                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
13125                 }
13126         }
13127
13128         if (cfg->lmf_var && cfg->method == method) {
13129                 cfg->cbb = init_localsbb;
13130                 emit_push_lmf (cfg);
13131         }
13132
13133         cfg->cbb = init_localsbb;
13134         emit_instrumentation_call (cfg, mono_profiler_method_enter);
13135
13136         if (seq_points) {
13137                 MonoBasicBlock *bb;
13138
13139                 /*
13140                  * Make seq points at backward branch targets interruptable.
13141                  */
13142                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
13143                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
13144                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
13145         }
13146
13147         /* Add a sequence point for method entry/exit events */
13148         if (seq_points && cfg->gen_sdb_seq_points) {
13149                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
13150                 MONO_ADD_INS (init_localsbb, ins);
13151                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
13152                 MONO_ADD_INS (cfg->bb_exit, ins);
13153         }
13154
13155         /*
13156          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
13157          * the code they refer to was dead (#11880).
13158          */
13159         if (sym_seq_points) {
13160                 for (i = 0; i < header->code_size; ++i) {
13161                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
13162                                 MonoInst *ins;
13163
13164                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
13165                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
13166                         }
13167                 }
13168         }
13169
13170         cfg->ip = NULL;
13171
13172         if (cfg->method == method) {
13173                 MonoBasicBlock *bb;
13174                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13175                         bb->region = mono_find_block_region (cfg, bb->real_offset);
13176                         if (cfg->spvars)
13177                                 mono_create_spvar_for_region (cfg, bb->region);
13178                         if (cfg->verbose_level > 2)
13179                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
13180                 }
13181         }
13182
13183         if (inline_costs < 0) {
13184                 char *mname;
13185
13186                 /* Method is too large */
13187                 mname = mono_method_full_name (method, TRUE);
13188                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
13189                 cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
13190                 g_free (mname);
13191         }
13192
13193         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
13194                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
13195
13196         goto cleanup;
13197
13198 mono_error_exit:
13199         g_assert (!mono_error_ok (&cfg->error));
13200         goto cleanup;
13201  
13202  exception_exit:
13203         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
13204         goto cleanup;
13205
13206  unverified:
13207         set_exception_type_from_invalid_il (cfg, method, ip);
13208         goto cleanup;
13209
13210  cleanup:
13211         g_slist_free (class_inits);
13212         mono_basic_block_free (original_bb);
13213         cfg->dont_inline = g_list_remove (cfg->dont_inline, method);
13214         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
13215         if (cfg->exception_type)
13216                 return -1;
13217         else
13218                 return inline_costs;
13219 }
13220
13221 static int
13222 store_membase_reg_to_store_membase_imm (int opcode)
13223 {
13224         switch (opcode) {
13225         case OP_STORE_MEMBASE_REG:
13226                 return OP_STORE_MEMBASE_IMM;
13227         case OP_STOREI1_MEMBASE_REG:
13228                 return OP_STOREI1_MEMBASE_IMM;
13229         case OP_STOREI2_MEMBASE_REG:
13230                 return OP_STOREI2_MEMBASE_IMM;
13231         case OP_STOREI4_MEMBASE_REG:
13232                 return OP_STOREI4_MEMBASE_IMM;
13233         case OP_STOREI8_MEMBASE_REG:
13234                 return OP_STOREI8_MEMBASE_IMM;
13235         default:
13236                 g_assert_not_reached ();
13237         }
13238
13239         return -1;
13240 }               
13241
13242 int
13243 mono_op_to_op_imm (int opcode)
13244 {
13245         switch (opcode) {
13246         case OP_IADD:
13247                 return OP_IADD_IMM;
13248         case OP_ISUB:
13249                 return OP_ISUB_IMM;
13250         case OP_IDIV:
13251                 return OP_IDIV_IMM;
13252         case OP_IDIV_UN:
13253                 return OP_IDIV_UN_IMM;
13254         case OP_IREM:
13255                 return OP_IREM_IMM;
13256         case OP_IREM_UN:
13257                 return OP_IREM_UN_IMM;
13258         case OP_IMUL:
13259                 return OP_IMUL_IMM;
13260         case OP_IAND:
13261                 return OP_IAND_IMM;
13262         case OP_IOR:
13263                 return OP_IOR_IMM;
13264         case OP_IXOR:
13265                 return OP_IXOR_IMM;
13266         case OP_ISHL:
13267                 return OP_ISHL_IMM;
13268         case OP_ISHR:
13269                 return OP_ISHR_IMM;
13270         case OP_ISHR_UN:
13271                 return OP_ISHR_UN_IMM;
13272
13273         case OP_LADD:
13274                 return OP_LADD_IMM;
13275         case OP_LSUB:
13276                 return OP_LSUB_IMM;
13277         case OP_LAND:
13278                 return OP_LAND_IMM;
13279         case OP_LOR:
13280                 return OP_LOR_IMM;
13281         case OP_LXOR:
13282                 return OP_LXOR_IMM;
13283         case OP_LSHL:
13284                 return OP_LSHL_IMM;
13285         case OP_LSHR:
13286                 return OP_LSHR_IMM;
13287         case OP_LSHR_UN:
13288                 return OP_LSHR_UN_IMM;
13289 #if SIZEOF_REGISTER == 8
13290         case OP_LREM:
13291                 return OP_LREM_IMM;
13292 #endif
13293
13294         case OP_COMPARE:
13295                 return OP_COMPARE_IMM;
13296         case OP_ICOMPARE:
13297                 return OP_ICOMPARE_IMM;
13298         case OP_LCOMPARE:
13299                 return OP_LCOMPARE_IMM;
13300
13301         case OP_STORE_MEMBASE_REG:
13302                 return OP_STORE_MEMBASE_IMM;
13303         case OP_STOREI1_MEMBASE_REG:
13304                 return OP_STOREI1_MEMBASE_IMM;
13305         case OP_STOREI2_MEMBASE_REG:
13306                 return OP_STOREI2_MEMBASE_IMM;
13307         case OP_STOREI4_MEMBASE_REG:
13308                 return OP_STOREI4_MEMBASE_IMM;
13309
13310 #if defined(TARGET_X86) || defined (TARGET_AMD64)
13311         case OP_X86_PUSH:
13312                 return OP_X86_PUSH_IMM;
13313         case OP_X86_COMPARE_MEMBASE_REG:
13314                 return OP_X86_COMPARE_MEMBASE_IMM;
13315 #endif
13316 #if defined(TARGET_AMD64)
13317         case OP_AMD64_ICOMPARE_MEMBASE_REG:
13318                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13319 #endif
13320         case OP_VOIDCALL_REG:
13321                 return OP_VOIDCALL;
13322         case OP_CALL_REG:
13323                 return OP_CALL;
13324         case OP_LCALL_REG:
13325                 return OP_LCALL;
13326         case OP_FCALL_REG:
13327                 return OP_FCALL;
13328         case OP_LOCALLOC:
13329                 return OP_LOCALLOC_IMM;
13330         }
13331
13332         return -1;
13333 }
13334
13335 static int
13336 ldind_to_load_membase (int opcode)
13337 {
13338         switch (opcode) {
13339         case CEE_LDIND_I1:
13340                 return OP_LOADI1_MEMBASE;
13341         case CEE_LDIND_U1:
13342                 return OP_LOADU1_MEMBASE;
13343         case CEE_LDIND_I2:
13344                 return OP_LOADI2_MEMBASE;
13345         case CEE_LDIND_U2:
13346                 return OP_LOADU2_MEMBASE;
13347         case CEE_LDIND_I4:
13348                 return OP_LOADI4_MEMBASE;
13349         case CEE_LDIND_U4:
13350                 return OP_LOADU4_MEMBASE;
13351         case CEE_LDIND_I:
13352                 return OP_LOAD_MEMBASE;
13353         case CEE_LDIND_REF:
13354                 return OP_LOAD_MEMBASE;
13355         case CEE_LDIND_I8:
13356                 return OP_LOADI8_MEMBASE;
13357         case CEE_LDIND_R4:
13358                 return OP_LOADR4_MEMBASE;
13359         case CEE_LDIND_R8:
13360                 return OP_LOADR8_MEMBASE;
13361         default:
13362                 g_assert_not_reached ();
13363         }
13364
13365         return -1;
13366 }
13367
13368 static int
13369 stind_to_store_membase (int opcode)
13370 {
13371         switch (opcode) {
13372         case CEE_STIND_I1:
13373                 return OP_STOREI1_MEMBASE_REG;
13374         case CEE_STIND_I2:
13375                 return OP_STOREI2_MEMBASE_REG;
13376         case CEE_STIND_I4:
13377                 return OP_STOREI4_MEMBASE_REG;
13378         case CEE_STIND_I:
13379         case CEE_STIND_REF:
13380                 return OP_STORE_MEMBASE_REG;
13381         case CEE_STIND_I8:
13382                 return OP_STOREI8_MEMBASE_REG;
13383         case CEE_STIND_R4:
13384                 return OP_STORER4_MEMBASE_REG;
13385         case CEE_STIND_R8:
13386                 return OP_STORER8_MEMBASE_REG;
13387         default:
13388                 g_assert_not_reached ();
13389         }
13390
13391         return -1;
13392 }
13393
13394 int
13395 mono_load_membase_to_load_mem (int opcode)
13396 {
13397         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
13398 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13399         switch (opcode) {
13400         case OP_LOAD_MEMBASE:
13401                 return OP_LOAD_MEM;
13402         case OP_LOADU1_MEMBASE:
13403                 return OP_LOADU1_MEM;
13404         case OP_LOADU2_MEMBASE:
13405                 return OP_LOADU2_MEM;
13406         case OP_LOADI4_MEMBASE:
13407                 return OP_LOADI4_MEM;
13408         case OP_LOADU4_MEMBASE:
13409                 return OP_LOADU4_MEM;
13410 #if SIZEOF_REGISTER == 8
13411         case OP_LOADI8_MEMBASE:
13412                 return OP_LOADI8_MEM;
13413 #endif
13414         }
13415 #endif
13416
13417         return -1;
13418 }
13419
13420 static inline int
13421 op_to_op_dest_membase (int store_opcode, int opcode)
13422 {
13423 #if defined(TARGET_X86)
13424         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
13425                 return -1;
13426
13427         switch (opcode) {
13428         case OP_IADD:
13429                 return OP_X86_ADD_MEMBASE_REG;
13430         case OP_ISUB:
13431                 return OP_X86_SUB_MEMBASE_REG;
13432         case OP_IAND:
13433                 return OP_X86_AND_MEMBASE_REG;
13434         case OP_IOR:
13435                 return OP_X86_OR_MEMBASE_REG;
13436         case OP_IXOR:
13437                 return OP_X86_XOR_MEMBASE_REG;
13438         case OP_ADD_IMM:
13439         case OP_IADD_IMM:
13440                 return OP_X86_ADD_MEMBASE_IMM;
13441         case OP_SUB_IMM:
13442         case OP_ISUB_IMM:
13443                 return OP_X86_SUB_MEMBASE_IMM;
13444         case OP_AND_IMM:
13445         case OP_IAND_IMM:
13446                 return OP_X86_AND_MEMBASE_IMM;
13447         case OP_OR_IMM:
13448         case OP_IOR_IMM:
13449                 return OP_X86_OR_MEMBASE_IMM;
13450         case OP_XOR_IMM:
13451         case OP_IXOR_IMM:
13452                 return OP_X86_XOR_MEMBASE_IMM;
13453         case OP_MOVE:
13454                 return OP_NOP;
13455         }
13456 #endif
13457
13458 #if defined(TARGET_AMD64)
13459         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
13460                 return -1;
13461
13462         switch (opcode) {
13463         case OP_IADD:
13464                 return OP_X86_ADD_MEMBASE_REG;
13465         case OP_ISUB:
13466                 return OP_X86_SUB_MEMBASE_REG;
13467         case OP_IAND:
13468                 return OP_X86_AND_MEMBASE_REG;
13469         case OP_IOR:
13470                 return OP_X86_OR_MEMBASE_REG;
13471         case OP_IXOR:
13472                 return OP_X86_XOR_MEMBASE_REG;
13473         case OP_IADD_IMM:
13474                 return OP_X86_ADD_MEMBASE_IMM;
13475         case OP_ISUB_IMM:
13476                 return OP_X86_SUB_MEMBASE_IMM;
13477         case OP_IAND_IMM:
13478                 return OP_X86_AND_MEMBASE_IMM;
13479         case OP_IOR_IMM:
13480                 return OP_X86_OR_MEMBASE_IMM;
13481         case OP_IXOR_IMM:
13482                 return OP_X86_XOR_MEMBASE_IMM;
13483         case OP_LADD:
13484                 return OP_AMD64_ADD_MEMBASE_REG;
13485         case OP_LSUB:
13486                 return OP_AMD64_SUB_MEMBASE_REG;
13487         case OP_LAND:
13488                 return OP_AMD64_AND_MEMBASE_REG;
13489         case OP_LOR:
13490                 return OP_AMD64_OR_MEMBASE_REG;
13491         case OP_LXOR:
13492                 return OP_AMD64_XOR_MEMBASE_REG;
13493         case OP_ADD_IMM:
13494         case OP_LADD_IMM:
13495                 return OP_AMD64_ADD_MEMBASE_IMM;
13496         case OP_SUB_IMM:
13497         case OP_LSUB_IMM:
13498                 return OP_AMD64_SUB_MEMBASE_IMM;
13499         case OP_AND_IMM:
13500         case OP_LAND_IMM:
13501                 return OP_AMD64_AND_MEMBASE_IMM;
13502         case OP_OR_IMM:
13503         case OP_LOR_IMM:
13504                 return OP_AMD64_OR_MEMBASE_IMM;
13505         case OP_XOR_IMM:
13506         case OP_LXOR_IMM:
13507                 return OP_AMD64_XOR_MEMBASE_IMM;
13508         case OP_MOVE:
13509                 return OP_NOP;
13510         }
13511 #endif
13512
13513         return -1;
13514 }
13515
13516 static inline int
13517 op_to_op_store_membase (int store_opcode, int opcode)
13518 {
13519 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13520         switch (opcode) {
13521         case OP_ICEQ:
13522                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13523                         return OP_X86_SETEQ_MEMBASE;
13524         case OP_CNE:
13525                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13526                         return OP_X86_SETNE_MEMBASE;
13527         }
13528 #endif
13529
13530         return -1;
13531 }
13532
13533 static inline int
13534 op_to_op_src1_membase (int load_opcode, int opcode)
13535 {
13536 #ifdef TARGET_X86
13537         /* FIXME: This has sign extension issues */
13538         /*
13539         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13540                 return OP_X86_COMPARE_MEMBASE8_IMM;
13541         */
13542
13543         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13544                 return -1;
13545
13546         switch (opcode) {
13547         case OP_X86_PUSH:
13548                 return OP_X86_PUSH_MEMBASE;
13549         case OP_COMPARE_IMM:
13550         case OP_ICOMPARE_IMM:
13551                 return OP_X86_COMPARE_MEMBASE_IMM;
13552         case OP_COMPARE:
13553         case OP_ICOMPARE:
13554                 return OP_X86_COMPARE_MEMBASE_REG;
13555         }
13556 #endif
13557
13558 #ifdef TARGET_AMD64
13559         /* FIXME: This has sign extension issues */
13560         /*
13561         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13562                 return OP_X86_COMPARE_MEMBASE8_IMM;
13563         */
13564
13565         switch (opcode) {
13566         case OP_X86_PUSH:
13567 #ifdef __mono_ilp32__
13568                 if (load_opcode == OP_LOADI8_MEMBASE)
13569 #else
13570                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13571 #endif
13572                         return OP_X86_PUSH_MEMBASE;
13573                 break;
13574                 /* FIXME: This only works for 32 bit immediates
13575         case OP_COMPARE_IMM:
13576         case OP_LCOMPARE_IMM:
13577                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13578                         return OP_AMD64_COMPARE_MEMBASE_IMM;
13579                 */
13580         case OP_ICOMPARE_IMM:
13581                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13582                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13583                 break;
13584         case OP_COMPARE:
13585         case OP_LCOMPARE:
13586 #ifdef __mono_ilp32__
13587                 if (load_opcode == OP_LOAD_MEMBASE)
13588                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13589                 if (load_opcode == OP_LOADI8_MEMBASE)
13590 #else
13591                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13592 #endif
13593                         return OP_AMD64_COMPARE_MEMBASE_REG;
13594                 break;
13595         case OP_ICOMPARE:
13596                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13597                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13598                 break;
13599         }
13600 #endif
13601
13602         return -1;
13603 }
13604
13605 static inline int
13606 op_to_op_src2_membase (int load_opcode, int opcode)
13607 {
13608 #ifdef TARGET_X86
13609         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13610                 return -1;
13611         
13612         switch (opcode) {
13613         case OP_COMPARE:
13614         case OP_ICOMPARE:
13615                 return OP_X86_COMPARE_REG_MEMBASE;
13616         case OP_IADD:
13617                 return OP_X86_ADD_REG_MEMBASE;
13618         case OP_ISUB:
13619                 return OP_X86_SUB_REG_MEMBASE;
13620         case OP_IAND:
13621                 return OP_X86_AND_REG_MEMBASE;
13622         case OP_IOR:
13623                 return OP_X86_OR_REG_MEMBASE;
13624         case OP_IXOR:
13625                 return OP_X86_XOR_REG_MEMBASE;
13626         }
13627 #endif
13628
13629 #ifdef TARGET_AMD64
13630 #ifdef __mono_ilp32__
13631         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE) ) {
13632 #else
13633         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)) {
13634 #endif
13635                 switch (opcode) {
13636                 case OP_ICOMPARE:
13637                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
13638                 case OP_IADD:
13639                         return OP_X86_ADD_REG_MEMBASE;
13640                 case OP_ISUB:
13641                         return OP_X86_SUB_REG_MEMBASE;
13642                 case OP_IAND:
13643                         return OP_X86_AND_REG_MEMBASE;
13644                 case OP_IOR:
13645                         return OP_X86_OR_REG_MEMBASE;
13646                 case OP_IXOR:
13647                         return OP_X86_XOR_REG_MEMBASE;
13648                 }
13649 #ifdef __mono_ilp32__
13650         } else if (load_opcode == OP_LOADI8_MEMBASE) {
13651 #else
13652         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE)) {
13653 #endif
13654                 switch (opcode) {
13655                 case OP_COMPARE:
13656                 case OP_LCOMPARE:
13657                         return OP_AMD64_COMPARE_REG_MEMBASE;
13658                 case OP_LADD:
13659                         return OP_AMD64_ADD_REG_MEMBASE;
13660                 case OP_LSUB:
13661                         return OP_AMD64_SUB_REG_MEMBASE;
13662                 case OP_LAND:
13663                         return OP_AMD64_AND_REG_MEMBASE;
13664                 case OP_LOR:
13665                         return OP_AMD64_OR_REG_MEMBASE;
13666                 case OP_LXOR:
13667                         return OP_AMD64_XOR_REG_MEMBASE;
13668                 }
13669         }
13670 #endif
13671
13672         return -1;
13673 }
13674
13675 int
13676 mono_op_to_op_imm_noemul (int opcode)
13677 {
13678         switch (opcode) {
13679 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
13680         case OP_LSHR:
13681         case OP_LSHL:
13682         case OP_LSHR_UN:
13683                 return -1;
13684 #endif
13685 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
13686         case OP_IDIV:
13687         case OP_IDIV_UN:
13688         case OP_IREM:
13689         case OP_IREM_UN:
13690                 return -1;
13691 #endif
13692 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
13693         case OP_IMUL:
13694                 return -1;
13695 #endif
13696         default:
13697                 return mono_op_to_op_imm (opcode);
13698         }
13699 }
13700
13701 /**
13702  * mono_handle_global_vregs:
13703  *
13704  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
13705  * for them.
13706  */
13707 void
13708 mono_handle_global_vregs (MonoCompile *cfg)
13709 {
13710         gint32 *vreg_to_bb;
13711         MonoBasicBlock *bb;
13712         int i, pos;
13713
13714         vreg_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
13715
13716 #ifdef MONO_ARCH_SIMD_INTRINSICS
13717         if (cfg->uses_simd_intrinsics)
13718                 mono_simd_simplify_indirection (cfg);
13719 #endif
13720
13721         /* Find local vregs used in more than one bb */
13722         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13723                 MonoInst *ins = bb->code;       
13724                 int block_num = bb->block_num;
13725
13726                 if (cfg->verbose_level > 2)
13727                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
13728
13729                 cfg->cbb = bb;
13730                 for (; ins; ins = ins->next) {
13731                         const char *spec = INS_INFO (ins->opcode);
13732                         int regtype = 0, regindex;
13733                         gint32 prev_bb;
13734
13735                         if (G_UNLIKELY (cfg->verbose_level > 2))
13736                                 mono_print_ins (ins);
13737
13738                         g_assert (ins->opcode >= MONO_CEE_LAST);
13739
13740                         for (regindex = 0; regindex < 4; regindex ++) {
13741                                 int vreg = 0;
13742
13743                                 if (regindex == 0) {
13744                                         regtype = spec [MONO_INST_DEST];
13745                                         if (regtype == ' ')
13746                                                 continue;
13747                                         vreg = ins->dreg;
13748                                 } else if (regindex == 1) {
13749                                         regtype = spec [MONO_INST_SRC1];
13750                                         if (regtype == ' ')
13751                                                 continue;
13752                                         vreg = ins->sreg1;
13753                                 } else if (regindex == 2) {
13754                                         regtype = spec [MONO_INST_SRC2];
13755                                         if (regtype == ' ')
13756                                                 continue;
13757                                         vreg = ins->sreg2;
13758                                 } else if (regindex == 3) {
13759                                         regtype = spec [MONO_INST_SRC3];
13760                                         if (regtype == ' ')
13761                                                 continue;
13762                                         vreg = ins->sreg3;
13763                                 }
13764
13765 #if SIZEOF_REGISTER == 4
13766                                 /* In the LLVM case, the long opcodes are not decomposed */
13767                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
13768                                         /*
13769                                          * Since some instructions reference the original long vreg,
13770                                          * and some reference the two component vregs, it is quite hard
13771                                          * to determine when it needs to be global. So be conservative.
13772                                          */
13773                                         if (!get_vreg_to_inst (cfg, vreg)) {
13774                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13775
13776                                                 if (cfg->verbose_level > 2)
13777                                                         printf ("LONG VREG R%d made global.\n", vreg);
13778                                         }
13779
13780                                         /*
13781                                          * Make the component vregs volatile since the optimizations can
13782                                          * get confused otherwise.
13783                                          */
13784                                         get_vreg_to_inst (cfg, vreg + 1)->flags |= MONO_INST_VOLATILE;
13785                                         get_vreg_to_inst (cfg, vreg + 2)->flags |= MONO_INST_VOLATILE;
13786                                 }
13787 #endif
13788
13789                                 g_assert (vreg != -1);
13790
13791                                 prev_bb = vreg_to_bb [vreg];
13792                                 if (prev_bb == 0) {
13793                                         /* 0 is a valid block num */
13794                                         vreg_to_bb [vreg] = block_num + 1;
13795                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
13796                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
13797                                                 continue;
13798
13799                                         if (!get_vreg_to_inst (cfg, vreg)) {
13800                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13801                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
13802
13803                                                 switch (regtype) {
13804                                                 case 'i':
13805                                                         if (vreg_is_ref (cfg, vreg))
13806                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
13807                                                         else
13808                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
13809                                                         break;
13810                                                 case 'l':
13811                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13812                                                         break;
13813                                                 case 'f':
13814                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
13815                                                         break;
13816                                                 case 'v':
13817                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
13818                                                         break;
13819                                                 default:
13820                                                         g_assert_not_reached ();
13821                                                 }
13822                                         }
13823
13824                                         /* Flag as having been used in more than one bb */
13825                                         vreg_to_bb [vreg] = -1;
13826                                 }
13827                         }
13828                 }
13829         }
13830
13831         /* If a variable is used in only one bblock, convert it into a local vreg */
13832         for (i = 0; i < cfg->num_varinfo; i++) {
13833                 MonoInst *var = cfg->varinfo [i];
13834                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
13835
13836                 switch (var->type) {
13837                 case STACK_I4:
13838                 case STACK_OBJ:
13839                 case STACK_PTR:
13840                 case STACK_MP:
13841                 case STACK_VTYPE:
13842 #if SIZEOF_REGISTER == 8
13843                 case STACK_I8:
13844 #endif
13845 #if !defined(TARGET_X86)
13846                 /* Enabling this screws up the fp stack on x86 */
13847                 case STACK_R8:
13848 #endif
13849                         if (mono_arch_is_soft_float ())
13850                                 break;
13851
13852                         /* Arguments are implicitly global */
13853                         /* Putting R4 vars into registers doesn't work currently */
13854                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
13855                         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) {
13856                                 /* 
13857                                  * Make that the variable's liveness interval doesn't contain a call, since
13858                                  * that would cause the lvreg to be spilled, making the whole optimization
13859                                  * useless.
13860                                  */
13861                                 /* This is too slow for JIT compilation */
13862 #if 0
13863                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
13864                                         MonoInst *ins;
13865                                         int def_index, call_index, ins_index;
13866                                         gboolean spilled = FALSE;
13867
13868                                         def_index = -1;
13869                                         call_index = -1;
13870                                         ins_index = 0;
13871                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
13872                                                 const char *spec = INS_INFO (ins->opcode);
13873
13874                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
13875                                                         def_index = ins_index;
13876
13877                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
13878                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
13879                                                         if (call_index > def_index) {
13880                                                                 spilled = TRUE;
13881                                                                 break;
13882                                                         }
13883                                                 }
13884
13885                                                 if (MONO_IS_CALL (ins))
13886                                                         call_index = ins_index;
13887
13888                                                 ins_index ++;
13889                                         }
13890
13891                                         if (spilled)
13892                                                 break;
13893                                 }
13894 #endif
13895
13896                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13897                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
13898                                 var->flags |= MONO_INST_IS_DEAD;
13899                                 cfg->vreg_to_inst [var->dreg] = NULL;
13900                         }
13901                         break;
13902                 }
13903         }
13904
13905         /* 
13906          * Compress the varinfo and vars tables so the liveness computation is faster and
13907          * takes up less space.
13908          */
13909         pos = 0;
13910         for (i = 0; i < cfg->num_varinfo; ++i) {
13911                 MonoInst *var = cfg->varinfo [i];
13912                 if (pos < i && cfg->locals_start == i)
13913                         cfg->locals_start = pos;
13914                 if (!(var->flags & MONO_INST_IS_DEAD)) {
13915                         if (pos < i) {
13916                                 cfg->varinfo [pos] = cfg->varinfo [i];
13917                                 cfg->varinfo [pos]->inst_c0 = pos;
13918                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
13919                                 cfg->vars [pos].idx = pos;
13920 #if SIZEOF_REGISTER == 4
13921                                 if (cfg->varinfo [pos]->type == STACK_I8) {
13922                                         /* Modify the two component vars too */
13923                                         MonoInst *var1;
13924
13925                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 1);
13926                                         var1->inst_c0 = pos;
13927                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 2);
13928                                         var1->inst_c0 = pos;
13929                                 }
13930 #endif
13931                         }
13932                         pos ++;
13933                 }
13934         }
13935         cfg->num_varinfo = pos;
13936         if (cfg->locals_start > cfg->num_varinfo)
13937                 cfg->locals_start = cfg->num_varinfo;
13938 }
13939
13940 /**
13941  * mono_spill_global_vars:
13942  *
13943  *   Generate spill code for variables which are not allocated to registers, 
13944  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
13945  * code is generated which could be optimized by the local optimization passes.
13946  */
13947 void
13948 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
13949 {
13950         MonoBasicBlock *bb;
13951         char spec2 [16];
13952         int orig_next_vreg;
13953         guint32 *vreg_to_lvreg;
13954         guint32 *lvregs;
13955         guint32 i, lvregs_len;
13956         gboolean dest_has_lvreg = FALSE;
13957         guint32 stacktypes [128];
13958         MonoInst **live_range_start, **live_range_end;
13959         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
13960         int *gsharedvt_vreg_to_idx = NULL;
13961
13962         *need_local_opts = FALSE;
13963
13964         memset (spec2, 0, sizeof (spec2));
13965
13966         /* FIXME: Move this function to mini.c */
13967         stacktypes ['i'] = STACK_PTR;
13968         stacktypes ['l'] = STACK_I8;
13969         stacktypes ['f'] = STACK_R8;
13970 #ifdef MONO_ARCH_SIMD_INTRINSICS
13971         stacktypes ['x'] = STACK_VTYPE;
13972 #endif
13973
13974 #if SIZEOF_REGISTER == 4
13975         /* Create MonoInsts for longs */
13976         for (i = 0; i < cfg->num_varinfo; i++) {
13977                 MonoInst *ins = cfg->varinfo [i];
13978
13979                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
13980                         switch (ins->type) {
13981                         case STACK_R8:
13982                         case STACK_I8: {
13983                                 MonoInst *tree;
13984
13985                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
13986                                         break;
13987
13988                                 g_assert (ins->opcode == OP_REGOFFSET);
13989
13990                                 tree = get_vreg_to_inst (cfg, ins->dreg + 1);
13991                                 g_assert (tree);
13992                                 tree->opcode = OP_REGOFFSET;
13993                                 tree->inst_basereg = ins->inst_basereg;
13994                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
13995
13996                                 tree = get_vreg_to_inst (cfg, ins->dreg + 2);
13997                                 g_assert (tree);
13998                                 tree->opcode = OP_REGOFFSET;
13999                                 tree->inst_basereg = ins->inst_basereg;
14000                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
14001                                 break;
14002                         }
14003                         default:
14004                                 break;
14005                         }
14006                 }
14007         }
14008 #endif
14009
14010         if (cfg->compute_gc_maps) {
14011                 /* registers need liveness info even for !non refs */
14012                 for (i = 0; i < cfg->num_varinfo; i++) {
14013                         MonoInst *ins = cfg->varinfo [i];
14014
14015                         if (ins->opcode == OP_REGVAR)
14016                                 ins->flags |= MONO_INST_GC_TRACK;
14017                 }
14018         }
14019
14020         if (cfg->gsharedvt) {
14021                 gsharedvt_vreg_to_idx = mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
14022
14023                 for (i = 0; i < cfg->num_varinfo; ++i) {
14024                         MonoInst *ins = cfg->varinfo [i];
14025                         int idx;
14026
14027                         if (mini_is_gsharedvt_variable_type (cfg, ins->inst_vtype)) {
14028                                 if (i >= cfg->locals_start) {
14029                                         /* Local */
14030                                         idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
14031                                         gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
14032                                         ins->opcode = OP_GSHAREDVT_LOCAL;
14033                                         ins->inst_imm = idx;
14034                                 } else {
14035                                         /* Arg */
14036                                         gsharedvt_vreg_to_idx [ins->dreg] = -1;
14037                                         ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
14038                                 }
14039                         }
14040                 }
14041         }
14042                 
14043         /* FIXME: widening and truncation */
14044
14045         /*
14046          * As an optimization, when a variable allocated to the stack is first loaded into 
14047          * an lvreg, we will remember the lvreg and use it the next time instead of loading
14048          * the variable again.
14049          */
14050         orig_next_vreg = cfg->next_vreg;
14051         vreg_to_lvreg = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
14052         lvregs = mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
14053         lvregs_len = 0;
14054
14055         /* 
14056          * These arrays contain the first and last instructions accessing a given
14057          * variable.
14058          * Since we emit bblocks in the same order we process them here, and we
14059          * don't split live ranges, these will precisely describe the live range of
14060          * the variable, i.e. the instruction range where a valid value can be found
14061          * in the variables location.
14062          * The live range is computed using the liveness info computed by the liveness pass.
14063          * We can't use vmv->range, since that is an abstract live range, and we need
14064          * one which is instruction precise.
14065          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
14066          */
14067         /* FIXME: Only do this if debugging info is requested */
14068         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
14069         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
14070         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
14071         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
14072         
14073         /* Add spill loads/stores */
14074         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
14075                 MonoInst *ins;
14076
14077                 if (cfg->verbose_level > 2)
14078                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
14079
14080                 /* Clear vreg_to_lvreg array */
14081                 for (i = 0; i < lvregs_len; i++)
14082                         vreg_to_lvreg [lvregs [i]] = 0;
14083                 lvregs_len = 0;
14084
14085                 cfg->cbb = bb;
14086                 MONO_BB_FOR_EACH_INS (bb, ins) {
14087                         const char *spec = INS_INFO (ins->opcode);
14088                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
14089                         gboolean store, no_lvreg;
14090                         int sregs [MONO_MAX_SRC_REGS];
14091
14092                         if (G_UNLIKELY (cfg->verbose_level > 2))
14093                                 mono_print_ins (ins);
14094
14095                         if (ins->opcode == OP_NOP)
14096                                 continue;
14097
14098                         /* 
14099                          * We handle LDADDR here as well, since it can only be decomposed
14100                          * when variable addresses are known.
14101                          */
14102                         if (ins->opcode == OP_LDADDR) {
14103                                 MonoInst *var = ins->inst_p0;
14104
14105                                 if (var->opcode == OP_VTARG_ADDR) {
14106                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
14107                                         MonoInst *vtaddr = var->inst_left;
14108                                         if (vtaddr->opcode == OP_REGVAR) {
14109                                                 ins->opcode = OP_MOVE;
14110                                                 ins->sreg1 = vtaddr->dreg;
14111                                         }
14112                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
14113                                                 ins->opcode = OP_LOAD_MEMBASE;
14114                                                 ins->inst_basereg = vtaddr->inst_basereg;
14115                                                 ins->inst_offset = vtaddr->inst_offset;
14116                                         } else
14117                                                 NOT_IMPLEMENTED;
14118                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg] < 0) {
14119                                         /* gsharedvt arg passed by ref */
14120                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
14121
14122                                         ins->opcode = OP_LOAD_MEMBASE;
14123                                         ins->inst_basereg = var->inst_basereg;
14124                                         ins->inst_offset = var->inst_offset;
14125                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg]) {
14126                                         MonoInst *load, *load2, *load3;
14127                                         int idx = gsharedvt_vreg_to_idx [var->dreg] - 1;
14128                                         int reg1, reg2, reg3;
14129                                         MonoInst *info_var = cfg->gsharedvt_info_var;
14130                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
14131
14132                                         /*
14133                                          * gsharedvt local.
14134                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
14135                                          */
14136
14137                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
14138
14139                                         g_assert (info_var);
14140                                         g_assert (locals_var);
14141
14142                                         /* Mark the instruction used to compute the locals var as used */
14143                                         cfg->gsharedvt_locals_var_ins = NULL;
14144
14145                                         /* Load the offset */
14146                                         if (info_var->opcode == OP_REGOFFSET) {
14147                                                 reg1 = alloc_ireg (cfg);
14148                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
14149                                         } else if (info_var->opcode == OP_REGVAR) {
14150                                                 load = NULL;
14151                                                 reg1 = info_var->dreg;
14152                                         } else {
14153                                                 g_assert_not_reached ();
14154                                         }
14155                                         reg2 = alloc_ireg (cfg);
14156                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
14157                                         /* Load the locals area address */
14158                                         reg3 = alloc_ireg (cfg);
14159                                         if (locals_var->opcode == OP_REGOFFSET) {
14160                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
14161                                         } else if (locals_var->opcode == OP_REGVAR) {
14162                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
14163                                         } else {
14164                                                 g_assert_not_reached ();
14165                                         }
14166                                         /* Compute the address */
14167                                         ins->opcode = OP_PADD;
14168                                         ins->sreg1 = reg3;
14169                                         ins->sreg2 = reg2;
14170
14171                                         mono_bblock_insert_before_ins (bb, ins, load3);
14172                                         mono_bblock_insert_before_ins (bb, load3, load2);
14173                                         if (load)
14174                                                 mono_bblock_insert_before_ins (bb, load2, load);
14175                                 } else {
14176                                         g_assert (var->opcode == OP_REGOFFSET);
14177
14178                                         ins->opcode = OP_ADD_IMM;
14179                                         ins->sreg1 = var->inst_basereg;
14180                                         ins->inst_imm = var->inst_offset;
14181                                 }
14182
14183                                 *need_local_opts = TRUE;
14184                                 spec = INS_INFO (ins->opcode);
14185                         }
14186
14187                         if (ins->opcode < MONO_CEE_LAST) {
14188                                 mono_print_ins (ins);
14189                                 g_assert_not_reached ();
14190                         }
14191
14192                         /*
14193                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
14194                          * src register.
14195                          * FIXME:
14196                          */
14197                         if (MONO_IS_STORE_MEMBASE (ins)) {
14198                                 tmp_reg = ins->dreg;
14199                                 ins->dreg = ins->sreg2;
14200                                 ins->sreg2 = tmp_reg;
14201                                 store = TRUE;
14202
14203                                 spec2 [MONO_INST_DEST] = ' ';
14204                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14205                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14206                                 spec2 [MONO_INST_SRC3] = ' ';
14207                                 spec = spec2;
14208                         } else if (MONO_IS_STORE_MEMINDEX (ins))
14209                                 g_assert_not_reached ();
14210                         else
14211                                 store = FALSE;
14212                         no_lvreg = FALSE;
14213
14214                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
14215                                 printf ("\t %.3s %d", spec, ins->dreg);
14216                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
14217                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
14218                                         printf (" %d", sregs [srcindex]);
14219                                 printf ("\n");
14220                         }
14221
14222                         /***************/
14223                         /*    DREG     */
14224                         /***************/
14225                         regtype = spec [MONO_INST_DEST];
14226                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
14227                         prev_dreg = -1;
14228
14229                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
14230                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
14231                                 MonoInst *store_ins;
14232                                 int store_opcode;
14233                                 MonoInst *def_ins = ins;
14234                                 int dreg = ins->dreg; /* The original vreg */
14235
14236                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
14237
14238                                 if (var->opcode == OP_REGVAR) {
14239                                         ins->dreg = var->dreg;
14240                                 } 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)) {
14241                                         /* 
14242                                          * Instead of emitting a load+store, use a _membase opcode.
14243                                          */
14244                                         g_assert (var->opcode == OP_REGOFFSET);
14245                                         if (ins->opcode == OP_MOVE) {
14246                                                 NULLIFY_INS (ins);
14247                                                 def_ins = NULL;
14248                                         } else {
14249                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
14250                                                 ins->inst_basereg = var->inst_basereg;
14251                                                 ins->inst_offset = var->inst_offset;
14252                                                 ins->dreg = -1;
14253                                         }
14254                                         spec = INS_INFO (ins->opcode);
14255                                 } else {
14256                                         guint32 lvreg;
14257
14258                                         g_assert (var->opcode == OP_REGOFFSET);
14259
14260                                         prev_dreg = ins->dreg;
14261
14262                                         /* Invalidate any previous lvreg for this vreg */
14263                                         vreg_to_lvreg [ins->dreg] = 0;
14264
14265                                         lvreg = 0;
14266
14267                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
14268                                                 regtype = 'l';
14269                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
14270                                         }
14271
14272                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
14273
14274 #if SIZEOF_REGISTER != 8
14275                                         if (regtype == 'l') {
14276                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET, ins->dreg + 1);
14277                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14278                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET, ins->dreg + 2);
14279                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14280                                                 def_ins = store_ins;
14281                                         }
14282                                         else
14283 #endif
14284                                         {
14285                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
14286
14287                                                 /* Try to fuse the store into the instruction itself */
14288                                                 /* FIXME: Add more instructions */
14289                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
14290                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
14291                                                         ins->inst_imm = ins->inst_c0;
14292                                                         ins->inst_destbasereg = var->inst_basereg;
14293                                                         ins->inst_offset = var->inst_offset;
14294                                                         spec = INS_INFO (ins->opcode);
14295                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE) || (ins->opcode == OP_RMOVE))) {
14296                                                         ins->opcode = store_opcode;
14297                                                         ins->inst_destbasereg = var->inst_basereg;
14298                                                         ins->inst_offset = var->inst_offset;
14299
14300                                                         no_lvreg = TRUE;
14301
14302                                                         tmp_reg = ins->dreg;
14303                                                         ins->dreg = ins->sreg2;
14304                                                         ins->sreg2 = tmp_reg;
14305                                                         store = TRUE;
14306
14307                                                         spec2 [MONO_INST_DEST] = ' ';
14308                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14309                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14310                                                         spec2 [MONO_INST_SRC3] = ' ';
14311                                                         spec = spec2;
14312                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
14313                                                         // FIXME: The backends expect the base reg to be in inst_basereg
14314                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
14315                                                         ins->dreg = -1;
14316                                                         ins->inst_basereg = var->inst_basereg;
14317                                                         ins->inst_offset = var->inst_offset;
14318                                                         spec = INS_INFO (ins->opcode);
14319                                                 } else {
14320                                                         /* printf ("INS: "); mono_print_ins (ins); */
14321                                                         /* Create a store instruction */
14322                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
14323
14324                                                         /* Insert it after the instruction */
14325                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
14326
14327                                                         def_ins = store_ins;
14328
14329                                                         /* 
14330                                                          * We can't assign ins->dreg to var->dreg here, since the
14331                                                          * sregs could use it. So set a flag, and do it after
14332                                                          * the sregs.
14333                                                          */
14334                                                         if ((!MONO_ARCH_USE_FPSTACK || ((store_opcode != OP_STORER8_MEMBASE_REG) && (store_opcode != OP_STORER4_MEMBASE_REG))) && !((var)->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT)))
14335                                                                 dest_has_lvreg = TRUE;
14336                                                 }
14337                                         }
14338                                 }
14339
14340                                 if (def_ins && !live_range_start [dreg]) {
14341                                         live_range_start [dreg] = def_ins;
14342                                         live_range_start_bb [dreg] = bb;
14343                                 }
14344
14345                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
14346                                         MonoInst *tmp;
14347
14348                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
14349                                         tmp->inst_c1 = dreg;
14350                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
14351                                 }
14352                         }
14353
14354                         /************/
14355                         /*  SREGS   */
14356                         /************/
14357                         num_sregs = mono_inst_get_src_registers (ins, sregs);
14358                         for (srcindex = 0; srcindex < 3; ++srcindex) {
14359                                 regtype = spec [MONO_INST_SRC1 + srcindex];
14360                                 sreg = sregs [srcindex];
14361
14362                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
14363                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
14364                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
14365                                         MonoInst *use_ins = ins;
14366                                         MonoInst *load_ins;
14367                                         guint32 load_opcode;
14368
14369                                         if (var->opcode == OP_REGVAR) {
14370                                                 sregs [srcindex] = var->dreg;
14371                                                 //mono_inst_set_src_registers (ins, sregs);
14372                                                 live_range_end [sreg] = use_ins;
14373                                                 live_range_end_bb [sreg] = bb;
14374
14375                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14376                                                         MonoInst *tmp;
14377
14378                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14379                                                         /* var->dreg is a hreg */
14380                                                         tmp->inst_c1 = sreg;
14381                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
14382                                                 }
14383
14384                                                 continue;
14385                                         }
14386
14387                                         g_assert (var->opcode == OP_REGOFFSET);
14388                                                 
14389                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
14390
14391                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
14392
14393                                         if (vreg_to_lvreg [sreg]) {
14394                                                 g_assert (vreg_to_lvreg [sreg] != -1);
14395
14396                                                 /* The variable is already loaded to an lvreg */
14397                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14398                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
14399                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
14400                                                 //mono_inst_set_src_registers (ins, sregs);
14401                                                 continue;
14402                                         }
14403
14404                                         /* Try to fuse the load into the instruction */
14405                                         if ((srcindex == 0) && (op_to_op_src1_membase (load_opcode, ins->opcode) != -1)) {
14406                                                 ins->opcode = op_to_op_src1_membase (load_opcode, ins->opcode);
14407                                                 sregs [0] = var->inst_basereg;
14408                                                 //mono_inst_set_src_registers (ins, sregs);
14409                                                 ins->inst_offset = var->inst_offset;
14410                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (load_opcode, ins->opcode) != -1)) {
14411                                                 ins->opcode = op_to_op_src2_membase (load_opcode, ins->opcode);
14412                                                 sregs [1] = var->inst_basereg;
14413                                                 //mono_inst_set_src_registers (ins, sregs);
14414                                                 ins->inst_offset = var->inst_offset;
14415                                         } else {
14416                                                 if (MONO_IS_REAL_MOVE (ins)) {
14417                                                         ins->opcode = OP_NOP;
14418                                                         sreg = ins->dreg;
14419                                                 } else {
14420                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
14421
14422                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
14423
14424                                                         if ((!MONO_ARCH_USE_FPSTACK || ((load_opcode != OP_LOADR8_MEMBASE) && (load_opcode != OP_LOADR4_MEMBASE))) && !((var)->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT)) && !no_lvreg) {
14425                                                                 if (var->dreg == prev_dreg) {
14426                                                                         /*
14427                                                                          * sreg refers to the value loaded by the load
14428                                                                          * emitted below, but we need to use ins->dreg
14429                                                                          * since it refers to the store emitted earlier.
14430                                                                          */
14431                                                                         sreg = ins->dreg;
14432                                                                 }
14433                                                                 g_assert (sreg != -1);
14434                                                                 vreg_to_lvreg [var->dreg] = sreg;
14435                                                                 g_assert (lvregs_len < 1024);
14436                                                                 lvregs [lvregs_len ++] = var->dreg;
14437                                                         }
14438                                                 }
14439
14440                                                 sregs [srcindex] = sreg;
14441                                                 //mono_inst_set_src_registers (ins, sregs);
14442
14443 #if SIZEOF_REGISTER != 8
14444                                                 if (regtype == 'l') {
14445                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 2, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
14446                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14447                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 1, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
14448                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14449                                                         use_ins = load_ins;
14450                                                 }
14451                                                 else
14452 #endif
14453                                                 {
14454 #if SIZEOF_REGISTER == 4
14455                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
14456 #endif
14457                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
14458                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14459                                                         use_ins = load_ins;
14460                                                 }
14461                                         }
14462
14463                                         if (var->dreg < orig_next_vreg) {
14464                                                 live_range_end [var->dreg] = use_ins;
14465                                                 live_range_end_bb [var->dreg] = bb;
14466                                         }
14467
14468                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14469                                                 MonoInst *tmp;
14470
14471                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14472                                                 tmp->inst_c1 = var->dreg;
14473                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
14474                                         }
14475                                 }
14476                         }
14477                         mono_inst_set_src_registers (ins, sregs);
14478
14479                         if (dest_has_lvreg) {
14480                                 g_assert (ins->dreg != -1);
14481                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
14482                                 g_assert (lvregs_len < 1024);
14483                                 lvregs [lvregs_len ++] = prev_dreg;
14484                                 dest_has_lvreg = FALSE;
14485                         }
14486
14487                         if (store) {
14488                                 tmp_reg = ins->dreg;
14489                                 ins->dreg = ins->sreg2;
14490                                 ins->sreg2 = tmp_reg;
14491                         }
14492
14493                         if (MONO_IS_CALL (ins)) {
14494                                 /* Clear vreg_to_lvreg array */
14495                                 for (i = 0; i < lvregs_len; i++)
14496                                         vreg_to_lvreg [lvregs [i]] = 0;
14497                                 lvregs_len = 0;
14498                         } else if (ins->opcode == OP_NOP) {
14499                                 ins->dreg = -1;
14500                                 MONO_INST_NULLIFY_SREGS (ins);
14501                         }
14502
14503                         if (cfg->verbose_level > 2)
14504                                 mono_print_ins_index (1, ins);
14505                 }
14506
14507                 /* Extend the live range based on the liveness info */
14508                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
14509                         for (i = 0; i < cfg->num_varinfo; i ++) {
14510                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
14511
14512                                 if (vreg_is_volatile (cfg, vi->vreg))
14513                                         /* The liveness info is incomplete */
14514                                         continue;
14515
14516                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
14517                                         /* Live from at least the first ins of this bb */
14518                                         live_range_start [vi->vreg] = bb->code;
14519                                         live_range_start_bb [vi->vreg] = bb;
14520                                 }
14521
14522                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
14523                                         /* Live at least until the last ins of this bb */
14524                                         live_range_end [vi->vreg] = bb->last_ins;
14525                                         live_range_end_bb [vi->vreg] = bb;
14526                                 }
14527                         }
14528                 }
14529         }
14530         
14531 #ifdef MONO_ARCH_HAVE_LIVERANGE_OPS
14532         /*
14533          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
14534          * by storing the current native offset into MonoMethodVar->live_range_start/end.
14535          */
14536         if (cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
14537                 for (i = 0; i < cfg->num_varinfo; ++i) {
14538                         int vreg = MONO_VARINFO (cfg, i)->vreg;
14539                         MonoInst *ins;
14540
14541                         if (live_range_start [vreg]) {
14542                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
14543                                 ins->inst_c0 = i;
14544                                 ins->inst_c1 = vreg;
14545                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
14546                         }
14547                         if (live_range_end [vreg]) {
14548                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
14549                                 ins->inst_c0 = i;
14550                                 ins->inst_c1 = vreg;
14551                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
14552                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
14553                                 else
14554                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
14555                         }
14556                 }
14557         }
14558 #endif
14559
14560         if (cfg->gsharedvt_locals_var_ins) {
14561                 /* Nullify if unused */
14562                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
14563                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
14564         }
14565
14566         g_free (live_range_start);
14567         g_free (live_range_end);
14568         g_free (live_range_start_bb);
14569         g_free (live_range_end_bb);
14570 }
14571
14572 /**
14573  * FIXME:
14574  * - use 'iadd' instead of 'int_add'
14575  * - handling ovf opcodes: decompose in method_to_ir.
14576  * - unify iregs/fregs
14577  *   -> partly done, the missing parts are:
14578  *   - a more complete unification would involve unifying the hregs as well, so
14579  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
14580  *     would no longer map to the machine hregs, so the code generators would need to
14581  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
14582  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
14583  *     fp/non-fp branches speeds it up by about 15%.
14584  * - use sext/zext opcodes instead of shifts
14585  * - add OP_ICALL
14586  * - get rid of TEMPLOADs if possible and use vregs instead
14587  * - clean up usage of OP_P/OP_ opcodes
14588  * - cleanup usage of DUMMY_USE
14589  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
14590  *   stack
14591  * - set the stack type and allocate a dreg in the EMIT_NEW macros
14592  * - get rid of all the <foo>2 stuff when the new JIT is ready.
14593  * - make sure handle_stack_args () is called before the branch is emitted
14594  * - when the new IR is done, get rid of all unused stuff
14595  * - COMPARE/BEQ as separate instructions or unify them ?
14596  *   - keeping them separate allows specialized compare instructions like
14597  *     compare_imm, compare_membase
14598  *   - most back ends unify fp compare+branch, fp compare+ceq
14599  * - integrate mono_save_args into inline_method
14600  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
14601  * - handle long shift opts on 32 bit platforms somehow: they require 
14602  *   3 sregs (2 for arg1 and 1 for arg2)
14603  * - make byref a 'normal' type.
14604  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
14605  *   variable if needed.
14606  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
14607  *   like inline_method.
14608  * - remove inlining restrictions
14609  * - fix LNEG and enable cfold of INEG
14610  * - generalize x86 optimizations like ldelema as a peephole optimization
14611  * - add store_mem_imm for amd64
14612  * - optimize the loading of the interruption flag in the managed->native wrappers
14613  * - avoid special handling of OP_NOP in passes
14614  * - move code inserting instructions into one function/macro.
14615  * - try a coalescing phase after liveness analysis
14616  * - add float -> vreg conversion + local optimizations on !x86
14617  * - figure out how to handle decomposed branches during optimizations, ie.
14618  *   compare+branch, op_jump_table+op_br etc.
14619  * - promote RuntimeXHandles to vregs
14620  * - vtype cleanups:
14621  *   - add a NEW_VARLOADA_VREG macro
14622  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
14623  *   accessing vtype fields.
14624  * - get rid of I8CONST on 64 bit platforms
14625  * - dealing with the increase in code size due to branches created during opcode
14626  *   decomposition:
14627  *   - use extended basic blocks
14628  *     - all parts of the JIT
14629  *     - handle_global_vregs () && local regalloc
14630  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
14631  * - sources of increase in code size:
14632  *   - vtypes
14633  *   - long compares
14634  *   - isinst and castclass
14635  *   - lvregs not allocated to global registers even if used multiple times
14636  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
14637  *   meaningful.
14638  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
14639  * - add all micro optimizations from the old JIT
14640  * - put tree optimizations into the deadce pass
14641  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
14642  *   specific function.
14643  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
14644  *   fcompare + branchCC.
14645  * - create a helper function for allocating a stack slot, taking into account 
14646  *   MONO_CFG_HAS_SPILLUP.
14647  * - merge r68207.
14648  * - merge the ia64 switch changes.
14649  * - optimize mono_regstate2_alloc_int/float.
14650  * - fix the pessimistic handling of variables accessed in exception handler blocks.
14651  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
14652  *   parts of the tree could be separated by other instructions, killing the tree
14653  *   arguments, or stores killing loads etc. Also, should we fold loads into other
14654  *   instructions if the result of the load is used multiple times ?
14655  * - make the REM_IMM optimization in mini-x86.c arch-independent.
14656  * - LAST MERGE: 108395.
14657  * - when returning vtypes in registers, generate IR and append it to the end of the
14658  *   last bb instead of doing it in the epilog.
14659  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
14660  */
14661
14662 /*
14663
14664 NOTES
14665 -----
14666
14667 - When to decompose opcodes:
14668   - earlier: this makes some optimizations hard to implement, since the low level IR
14669   no longer contains the neccessary information. But it is easier to do.
14670   - later: harder to implement, enables more optimizations.
14671 - Branches inside bblocks:
14672   - created when decomposing complex opcodes. 
14673     - branches to another bblock: harmless, but not tracked by the branch 
14674       optimizations, so need to branch to a label at the start of the bblock.
14675     - branches to inside the same bblock: very problematic, trips up the local
14676       reg allocator. Can be fixed by spitting the current bblock, but that is a
14677       complex operation, since some local vregs can become global vregs etc.
14678 - Local/global vregs:
14679   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
14680     local register allocator.
14681   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
14682     structure, created by mono_create_var (). Assigned to hregs or the stack by
14683     the global register allocator.
14684 - When to do optimizations like alu->alu_imm:
14685   - earlier -> saves work later on since the IR will be smaller/simpler
14686   - later -> can work on more instructions
14687 - Handling of valuetypes:
14688   - When a vtype is pushed on the stack, a new temporary is created, an 
14689     instruction computing its address (LDADDR) is emitted and pushed on
14690     the stack. Need to optimize cases when the vtype is used immediately as in
14691     argument passing, stloc etc.
14692 - Instead of the to_end stuff in the old JIT, simply call the function handling
14693   the values on the stack before emitting the last instruction of the bb.
14694 */
14695
14696 #endif /* DISABLE_JIT */