[mini] Use the array fast path with array magic interfaces. Do the expensive check...
[mono.git] / mono / mini / method-to-ir.c
1 /*
2  * method-to-ir.c: Convert CIL to the JIT internal representation
3  *
4  * Author:
5  *   Paolo Molaro (lupus@ximian.com)
6  *   Dietmar Maurer (dietmar@ximian.com)
7  *
8  * (C) 2002 Ximian, Inc.
9  * Copyright 2003-2010 Novell, Inc (http://www.novell.com)
10  * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
11  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
12  */
13
14 #include <config.h>
15 #include <mono/utils/mono-compiler.h>
16
17 #ifndef DISABLE_JIT
18
19 #include <signal.h>
20
21 #ifdef HAVE_UNISTD_H
22 #include <unistd.h>
23 #endif
24
25 #include <math.h>
26 #include <string.h>
27 #include <ctype.h>
28
29 #ifdef HAVE_SYS_TIME_H
30 #include <sys/time.h>
31 #endif
32
33 #ifdef HAVE_ALLOCA_H
34 #include <alloca.h>
35 #endif
36
37 #include <mono/utils/memcheck.h>
38 #include "mini.h"
39 #include <mono/metadata/abi-details.h>
40 #include <mono/metadata/assembly.h>
41 #include <mono/metadata/attrdefs.h>
42 #include <mono/metadata/loader.h>
43 #include <mono/metadata/tabledefs.h>
44 #include <mono/metadata/class.h>
45 #include <mono/metadata/object.h>
46 #include <mono/metadata/exception.h>
47 #include <mono/metadata/opcodes.h>
48 #include <mono/metadata/mono-endian.h>
49 #include <mono/metadata/tokentype.h>
50 #include <mono/metadata/tabledefs.h>
51 #include <mono/metadata/marshal.h>
52 #include <mono/metadata/debug-helpers.h>
53 #include <mono/metadata/mono-debug.h>
54 #include <mono/metadata/mono-debug-debugger.h>
55 #include <mono/metadata/gc-internals.h>
56 #include <mono/metadata/security-manager.h>
57 #include <mono/metadata/threads-types.h>
58 #include <mono/metadata/security-core-clr.h>
59 #include <mono/metadata/profiler-private.h>
60 #include <mono/metadata/profiler.h>
61 #include <mono/metadata/monitor.h>
62 #include <mono/metadata/debug-mono-symfile.h>
63 #include <mono/utils/mono-compiler.h>
64 #include <mono/utils/mono-memory-model.h>
65 #include <mono/utils/mono-error-internals.h>
66 #include <mono/metadata/mono-basic-block.h>
67 #include <mono/metadata/reflection-internals.h>
68 #include <mono/utils/mono-threads-coop.h>
69
70 #include "trace.h"
71
72 #include "ir-emit.h"
73
74 #include "jit-icalls.h"
75 #include "jit.h"
76 #include "debugger-agent.h"
77 #include "seq-points.h"
78 #include "aot-compiler.h"
79 #include "mini-llvm.h"
80
81 #define BRANCH_COST 10
82 #define INLINE_LENGTH_LIMIT 20
83
84 /* These have 'cfg' as an implicit argument */
85 #define INLINE_FAILURE(msg) do {                                                                        \
86         if ((cfg->method != cfg->current_method) && (cfg->current_method->wrapper_type == MONO_WRAPPER_NONE)) { \
87                 inline_failure (cfg, msg);                                                                              \
88                 goto exception_exit;                                                                                    \
89         } \
90         } while (0)
91 #define CHECK_CFG_EXCEPTION do {\
92                 if (cfg->exception_type != MONO_EXCEPTION_NONE) \
93                         goto exception_exit;                                            \
94         } while (0)
95 #define FIELD_ACCESS_FAILURE(method, field) do {                                        \
96                 field_access_failure ((cfg), (method), (field));                        \
97                 goto exception_exit;    \
98         } while (0)
99 #define GENERIC_SHARING_FAILURE(opcode) do {            \
100                 if (cfg->gshared) {                                                                     \
101                         gshared_failure (cfg, opcode, __FILE__, __LINE__);      \
102                         goto exception_exit;    \
103                 }                       \
104         } while (0)
105 #define GSHAREDVT_FAILURE(opcode) do {          \
106         if (cfg->gsharedvt) {                                                                                           \
107                 gsharedvt_failure (cfg, opcode, __FILE__, __LINE__);                    \
108                 goto exception_exit;                                                                                    \
109         }                                                                                                                                       \
110         } while (0)
111 #define OUT_OF_MEMORY_FAILURE do {      \
112                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);                \
113                 mono_error_set_out_of_memory (&cfg->error, "");                                 \
114                 goto exception_exit;    \
115         } while (0)
116 #define DISABLE_AOT(cfg) do { \
117                 if ((cfg)->verbose_level >= 2)                                            \
118                         printf ("AOT disabled: %s:%d\n", __FILE__, __LINE__);   \
119                 (cfg)->disable_aot = TRUE;                                                        \
120         } while (0)
121 #define LOAD_ERROR do { \
122                 break_on_unverified ();                                                         \
123                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD); \
124                 goto exception_exit;                                                                    \
125         } while (0)
126
127 #define TYPE_LOAD_ERROR(klass) do { \
128                 cfg->exception_ptr = klass; \
129                 LOAD_ERROR;                                     \
130         } while (0)
131
132 #define CHECK_CFG_ERROR do {\
133                 if (!mono_error_ok (&cfg->error)) { \
134                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);        \
135                         goto mono_error_exit; \
136                 } \
137         } while (0)
138
139 /* Determine whenever 'ins' represents a load of the 'this' argument */
140 #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && ((ins)->opcode == OP_MOVE) && ((ins)->sreg1 == cfg->args [0]->dreg))
141
142 static int ldind_to_load_membase (int opcode);
143 static int stind_to_store_membase (int opcode);
144
145 int mono_op_to_op_imm (int opcode);
146 int mono_op_to_op_imm_noemul (int opcode);
147
148 MONO_API MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
149
150 static int inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
151                                                   guchar *ip, guint real_offset, gboolean inline_always);
152 static MonoInst*
153 emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used, MonoInst **sp);
154
155 /* helper methods signatures */
156 static MonoMethodSignature *helper_sig_domain_get;
157 static MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline;
158 static MonoMethodSignature *helper_sig_llvmonly_imt_trampoline;
159
160 /* type loading helpers */
161 static GENERATE_GET_CLASS_WITH_CACHE (runtime_helpers, System.Runtime.CompilerServices, RuntimeHelpers)
162 static GENERATE_TRY_GET_CLASS_WITH_CACHE (debuggable_attribute, System.Diagnostics, DebuggableAttribute)
163
164 /*
165  * Instruction metadata
166  */
167 #ifdef MINI_OP
168 #undef MINI_OP
169 #endif
170 #ifdef MINI_OP3
171 #undef MINI_OP3
172 #endif
173 #define MINI_OP(a,b,dest,src1,src2) dest, src1, src2, ' ',
174 #define MINI_OP3(a,b,dest,src1,src2,src3) dest, src1, src2, src3,
175 #define NONE ' '
176 #define IREG 'i'
177 #define FREG 'f'
178 #define VREG 'v'
179 #define XREG 'x'
180 #if SIZEOF_REGISTER == 8 && SIZEOF_REGISTER == SIZEOF_VOID_P
181 #define LREG IREG
182 #else
183 #define LREG 'l'
184 #endif
185 /* keep in sync with the enum in mini.h */
186 const char
187 ins_info[] = {
188 #include "mini-ops.h"
189 };
190 #undef MINI_OP
191 #undef MINI_OP3
192
193 #define MINI_OP(a,b,dest,src1,src2) ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0)),
194 #define MINI_OP3(a,b,dest,src1,src2,src3) ((src3) != NONE ? 3 : ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0))),
195 /* 
196  * This should contain the index of the last sreg + 1. This is not the same
197  * as the number of sregs for opcodes like IA64_CMP_EQ_IMM.
198  */
199 const gint8 ins_sreg_counts[] = {
200 #include "mini-ops.h"
201 };
202 #undef MINI_OP
203 #undef MINI_OP3
204
205 #define MONO_INIT_VARINFO(vi,id) do { \
206         (vi)->range.first_use.pos.bid = 0xffff; \
207         (vi)->reg = -1; \
208         (vi)->idx = (id); \
209 } while (0)
210
211 guint32
212 mono_alloc_ireg (MonoCompile *cfg)
213 {
214         return alloc_ireg (cfg);
215 }
216
217 guint32
218 mono_alloc_lreg (MonoCompile *cfg)
219 {
220         return alloc_lreg (cfg);
221 }
222
223 guint32
224 mono_alloc_freg (MonoCompile *cfg)
225 {
226         return alloc_freg (cfg);
227 }
228
229 guint32
230 mono_alloc_preg (MonoCompile *cfg)
231 {
232         return alloc_preg (cfg);
233 }
234
235 guint32
236 mono_alloc_dreg (MonoCompile *cfg, MonoStackType stack_type)
237 {
238         return alloc_dreg (cfg, stack_type);
239 }
240
241 /*
242  * mono_alloc_ireg_ref:
243  *
244  *   Allocate an IREG, and mark it as holding a GC ref.
245  */
246 guint32
247 mono_alloc_ireg_ref (MonoCompile *cfg)
248 {
249         return alloc_ireg_ref (cfg);
250 }
251
252 /*
253  * mono_alloc_ireg_mp:
254  *
255  *   Allocate an IREG, and mark it as holding a managed pointer.
256  */
257 guint32
258 mono_alloc_ireg_mp (MonoCompile *cfg)
259 {
260         return alloc_ireg_mp (cfg);
261 }
262
263 /*
264  * mono_alloc_ireg_copy:
265  *
266  *   Allocate an IREG with the same GC type as VREG.
267  */
268 guint32
269 mono_alloc_ireg_copy (MonoCompile *cfg, guint32 vreg)
270 {
271         if (vreg_is_ref (cfg, vreg))
272                 return alloc_ireg_ref (cfg);
273         else if (vreg_is_mp (cfg, vreg))
274                 return alloc_ireg_mp (cfg);
275         else
276                 return alloc_ireg (cfg);
277 }
278
279 guint
280 mono_type_to_regmove (MonoCompile *cfg, MonoType *type)
281 {
282         if (type->byref)
283                 return OP_MOVE;
284
285         type = mini_get_underlying_type (type);
286 handle_enum:
287         switch (type->type) {
288         case MONO_TYPE_I1:
289         case MONO_TYPE_U1:
290                 return OP_MOVE;
291         case MONO_TYPE_I2:
292         case MONO_TYPE_U2:
293                 return OP_MOVE;
294         case MONO_TYPE_I4:
295         case MONO_TYPE_U4:
296                 return OP_MOVE;
297         case MONO_TYPE_I:
298         case MONO_TYPE_U:
299         case MONO_TYPE_PTR:
300         case MONO_TYPE_FNPTR:
301                 return OP_MOVE;
302         case MONO_TYPE_CLASS:
303         case MONO_TYPE_STRING:
304         case MONO_TYPE_OBJECT:
305         case MONO_TYPE_SZARRAY:
306         case MONO_TYPE_ARRAY:    
307                 return OP_MOVE;
308         case MONO_TYPE_I8:
309         case MONO_TYPE_U8:
310 #if SIZEOF_REGISTER == 8
311                 return OP_MOVE;
312 #else
313                 return OP_LMOVE;
314 #endif
315         case MONO_TYPE_R4:
316                 return cfg->r4fp ? OP_RMOVE : OP_FMOVE;
317         case MONO_TYPE_R8:
318                 return OP_FMOVE;
319         case MONO_TYPE_VALUETYPE:
320                 if (type->data.klass->enumtype) {
321                         type = mono_class_enum_basetype (type->data.klass);
322                         goto handle_enum;
323                 }
324                 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
325                         return OP_XMOVE;
326                 return OP_VMOVE;
327         case MONO_TYPE_TYPEDBYREF:
328                 return OP_VMOVE;
329         case MONO_TYPE_GENERICINST:
330                 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
331                         return OP_XMOVE;
332                 type = &type->data.generic_class->container_class->byval_arg;
333                 goto handle_enum;
334         case MONO_TYPE_VAR:
335         case MONO_TYPE_MVAR:
336                 g_assert (cfg->gshared);
337                 if (mini_type_var_is_vt (type))
338                         return OP_VMOVE;
339                 else
340                         return mono_type_to_regmove (cfg, mini_get_underlying_type (type));
341         default:
342                 g_error ("unknown type 0x%02x in type_to_regstore", type->type);
343         }
344         return -1;
345 }
346
347 void
348 mono_print_bb (MonoBasicBlock *bb, const char *msg)
349 {
350         int i;
351         MonoInst *tree;
352
353         printf ("\n%s %d: [IN: ", msg, bb->block_num);
354         for (i = 0; i < bb->in_count; ++i)
355                 printf (" BB%d(%d)", bb->in_bb [i]->block_num, bb->in_bb [i]->dfn);
356         printf (", OUT: ");
357         for (i = 0; i < bb->out_count; ++i)
358                 printf (" BB%d(%d)", bb->out_bb [i]->block_num, bb->out_bb [i]->dfn);
359         printf (" ]\n");
360         for (tree = bb->code; tree; tree = tree->next)
361                 mono_print_ins_index (-1, tree);
362 }
363
364 void
365 mono_create_helper_signatures (void)
366 {
367         helper_sig_domain_get = mono_create_icall_signature ("ptr");
368         helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
369         helper_sig_llvmonly_imt_trampoline = mono_create_icall_signature ("ptr ptr ptr");
370 }
371
372 static MONO_NEVER_INLINE void
373 break_on_unverified (void)
374 {
375         if (mini_get_debug_options ()->break_on_unverified)
376                 G_BREAKPOINT ();
377 }
378
379 static MONO_NEVER_INLINE void
380 field_access_failure (MonoCompile *cfg, MonoMethod *method, MonoClassField *field)
381 {
382         char *method_fname = mono_method_full_name (method, TRUE);
383         char *field_fname = mono_field_full_name (field);
384         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
385         mono_error_set_generic_error (&cfg->error, "System", "FieldAccessException", "Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname);
386         g_free (method_fname);
387         g_free (field_fname);
388 }
389
390 static MONO_NEVER_INLINE void
391 inline_failure (MonoCompile *cfg, const char *msg)
392 {
393         if (cfg->verbose_level >= 2)
394                 printf ("inline failed: %s\n", msg);
395         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INLINE_FAILED);
396 }
397
398 static MONO_NEVER_INLINE void
399 gshared_failure (MonoCompile *cfg, int opcode, const char *file, int line)
400 {
401         if (cfg->verbose_level > 2)                                                                                     \
402                 printf ("sharing failed for method %s.%s.%s/%d opcode %s line %d\n", cfg->current_method->klass->name_space, cfg->current_method->klass->name, cfg->current_method->name, cfg->current_method->signature->param_count, mono_opcode_name ((opcode)), line);
403         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
404 }
405
406 static MONO_NEVER_INLINE void
407 gsharedvt_failure (MonoCompile *cfg, int opcode, const char *file, int line)
408 {
409         cfg->exception_message = g_strdup_printf ("gsharedvt failed for method %s.%s.%s/%d opcode %s %s:%d", cfg->current_method->klass->name_space, cfg->current_method->klass->name, cfg->current_method->name, cfg->current_method->signature->param_count, mono_opcode_name ((opcode)), file, line);
410         if (cfg->verbose_level >= 2)
411                 printf ("%s\n", cfg->exception_message);
412         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
413 }
414
415 /*
416  * When using gsharedvt, some instatiations might be verifiable, and some might be not. i.e. 
417  * foo<T> (int i) { ldarg.0; box T; }
418  */
419 #define UNVERIFIED do { \
420         if (cfg->gsharedvt) { \
421                 if (cfg->verbose_level > 2)                                                                     \
422                         printf ("gsharedvt method failed to verify, falling back to instantiation.\n"); \
423                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \
424                 goto exception_exit;                                                                                    \
425         }                                                                                                                                       \
426         break_on_unverified ();                                                                                         \
427         goto unverified;                                                                                                        \
428 } while (0)
429
430 #define GET_BBLOCK(cfg,tblock,ip) do {  \
431                 (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
432                 if (!(tblock)) {        \
433                         if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
434             NEW_BBLOCK (cfg, (tblock)); \
435                         (tblock)->cil_code = (ip);      \
436                         ADD_BBLOCK (cfg, (tblock));     \
437                 } \
438         } while (0)
439
440 #if defined(TARGET_X86) || defined(TARGET_AMD64)
441 #define EMIT_NEW_X86_LEA(cfg,dest,sr1,sr2,shift,imm) do { \
442                 MONO_INST_NEW (cfg, dest, OP_X86_LEA); \
443                 (dest)->dreg = alloc_ireg_mp ((cfg)); \
444                 (dest)->sreg1 = (sr1); \
445                 (dest)->sreg2 = (sr2); \
446                 (dest)->inst_imm = (imm); \
447                 (dest)->backend.shift_amount = (shift); \
448                 MONO_ADD_INS ((cfg)->cbb, (dest)); \
449         } while (0)
450 #endif
451
452 /* Emit conversions so both operands of a binary opcode are of the same type */
453 static void
454 add_widen_op (MonoCompile *cfg, MonoInst *ins, MonoInst **arg1_ref, MonoInst **arg2_ref)
455 {
456         MonoInst *arg1 = *arg1_ref;
457         MonoInst *arg2 = *arg2_ref;
458
459         if (cfg->r4fp &&
460                 ((arg1->type == STACK_R4 && arg2->type == STACK_R8) ||
461                  (arg1->type == STACK_R8 && arg2->type == STACK_R4))) {
462                 MonoInst *conv;
463
464                 /* Mixing r4/r8 is allowed by the spec */
465                 if (arg1->type == STACK_R4) {
466                         int dreg = alloc_freg (cfg);
467
468                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg1->dreg);
469                         conv->type = STACK_R8;
470                         ins->sreg1 = dreg;
471                         *arg1_ref = conv;
472                 }
473                 if (arg2->type == STACK_R4) {
474                         int dreg = alloc_freg (cfg);
475
476                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg2->dreg);
477                         conv->type = STACK_R8;
478                         ins->sreg2 = dreg;
479                         *arg2_ref = conv;
480                 }
481         }
482
483 #if SIZEOF_REGISTER == 8
484         /* FIXME: Need to add many more cases */
485         if ((arg1)->type == STACK_PTR && (arg2)->type == STACK_I4) {
486                 MonoInst *widen;
487
488                 int dr = alloc_preg (cfg);
489                 EMIT_NEW_UNALU (cfg, widen, OP_SEXT_I4, dr, (arg2)->dreg);
490                 (ins)->sreg2 = widen->dreg;
491         }
492 #endif
493 }
494
495 #define ADD_BINOP(op) do {      \
496                 MONO_INST_NEW (cfg, ins, (op)); \
497                 sp -= 2;        \
498                 ins->sreg1 = sp [0]->dreg;      \
499                 ins->sreg2 = sp [1]->dreg;      \
500                 type_from_op (cfg, ins, sp [0], sp [1]);        \
501                 CHECK_TYPE (ins);       \
502                 /* Have to insert a widening op */               \
503         add_widen_op (cfg, ins, &sp [0], &sp [1]);               \
504         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type); \
505         MONO_ADD_INS ((cfg)->cbb, (ins)); \
506         *sp++ = mono_decompose_opcode ((cfg), (ins));   \
507         } while (0)
508
509 #define ADD_UNOP(op) do {       \
510                 MONO_INST_NEW (cfg, ins, (op)); \
511                 sp--;   \
512                 ins->sreg1 = sp [0]->dreg;      \
513                 type_from_op (cfg, ins, sp [0], NULL);  \
514                 CHECK_TYPE (ins);       \
515         (ins)->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type); \
516         MONO_ADD_INS ((cfg)->cbb, (ins)); \
517                 *sp++ = mono_decompose_opcode (cfg, ins);       \
518         } while (0)
519
520 #define ADD_BINCOND(next_block) do {    \
521                 MonoInst *cmp;  \
522                 sp -= 2; \
523                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
524                 cmp->sreg1 = sp [0]->dreg;      \
525                 cmp->sreg2 = sp [1]->dreg;      \
526                 type_from_op (cfg, cmp, sp [0], sp [1]);        \
527                 CHECK_TYPE (cmp);       \
528                 add_widen_op (cfg, cmp, &sp [0], &sp [1]);                                              \
529                 type_from_op (cfg, ins, sp [0], sp [1]);                                                        \
530                 ins->inst_many_bb = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);   \
531                 GET_BBLOCK (cfg, tblock, target);               \
532                 link_bblock (cfg, cfg->cbb, tblock);    \
533                 ins->inst_true_bb = tblock;     \
534                 if ((next_block)) {     \
535                         link_bblock (cfg, cfg->cbb, (next_block));      \
536                         ins->inst_false_bb = (next_block);      \
537                         start_new_bblock = 1;   \
538                 } else {        \
539                         GET_BBLOCK (cfg, tblock, ip);           \
540                         link_bblock (cfg, cfg->cbb, tblock);    \
541                         ins->inst_false_bb = tblock;    \
542                         start_new_bblock = 2;   \
543                 }       \
544                 if (sp != stack_start) {                                                                        \
545                     handle_stack_args (cfg, stack_start, sp - stack_start); \
546                         CHECK_UNVERIFIABLE (cfg); \
547                 } \
548         MONO_ADD_INS (cfg->cbb, cmp); \
549                 MONO_ADD_INS (cfg->cbb, ins);   \
550         } while (0)
551
552 /* *
553  * link_bblock: Links two basic blocks
554  *
555  * links two basic blocks in the control flow graph, the 'from'
556  * argument is the starting block and the 'to' argument is the block
557  * the control flow ends to after 'from'.
558  */
559 static void
560 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
561 {
562         MonoBasicBlock **newa;
563         int i, found;
564
565 #if 0
566         if (from->cil_code) {
567                 if (to->cil_code)
568                         printf ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
569                 else
570                         printf ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
571         } else {
572                 if (to->cil_code)
573                         printf ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
574                 else
575                         printf ("edge from entry to exit\n");
576         }
577 #endif
578
579         found = FALSE;
580         for (i = 0; i < from->out_count; ++i) {
581                 if (to == from->out_bb [i]) {
582                         found = TRUE;
583                         break;
584                 }
585         }
586         if (!found) {
587                 newa = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
588                 for (i = 0; i < from->out_count; ++i) {
589                         newa [i] = from->out_bb [i];
590                 }
591                 newa [i] = to;
592                 from->out_count++;
593                 from->out_bb = newa;
594         }
595
596         found = FALSE;
597         for (i = 0; i < to->in_count; ++i) {
598                 if (from == to->in_bb [i]) {
599                         found = TRUE;
600                         break;
601                 }
602         }
603         if (!found) {
604                 newa = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
605                 for (i = 0; i < to->in_count; ++i) {
606                         newa [i] = to->in_bb [i];
607                 }
608                 newa [i] = from;
609                 to->in_count++;
610                 to->in_bb = newa;
611         }
612 }
613
614 void
615 mono_link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
616 {
617         link_bblock (cfg, from, to);
618 }
619
620 /**
621  * mono_find_block_region:
622  *
623  *   We mark each basic block with a region ID. We use that to avoid BB
624  *   optimizations when blocks are in different regions.
625  *
626  * Returns:
627  *   A region token that encodes where this region is, and information
628  *   about the clause owner for this block.
629  *
630  *   The region encodes the try/catch/filter clause that owns this block
631  *   as well as the type.  -1 is a special value that represents a block
632  *   that is in none of try/catch/filter.
633  */
634 static int
635 mono_find_block_region (MonoCompile *cfg, int offset)
636 {
637         MonoMethodHeader *header = cfg->header;
638         MonoExceptionClause *clause;
639         int i;
640
641         for (i = 0; i < header->num_clauses; ++i) {
642                 clause = &header->clauses [i];
643                 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
644                     (offset < (clause->handler_offset)))
645                         return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
646                            
647                 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
648                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
649                                 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
650                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
651                                 return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
652                         else
653                                 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
654                 }
655         }
656         for (i = 0; i < header->num_clauses; ++i) {
657                 clause = &header->clauses [i];
658
659                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
660                         return ((i + 1) << 8) | clause->flags;
661         }
662
663         return -1;
664 }
665
666 static gboolean
667 ip_in_finally_clause (MonoCompile *cfg, int offset)
668 {
669         MonoMethodHeader *header = cfg->header;
670         MonoExceptionClause *clause;
671         int i;
672
673         for (i = 0; i < header->num_clauses; ++i) {
674                 clause = &header->clauses [i];
675                 if (clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FAULT)
676                         continue;
677
678                 if (MONO_OFFSET_IN_HANDLER (clause, offset))
679                         return TRUE;
680         }
681         return FALSE;
682 }
683
684 static GList*
685 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
686 {
687         MonoMethodHeader *header = cfg->header;
688         MonoExceptionClause *clause;
689         int i;
690         GList *res = NULL;
691
692         for (i = 0; i < header->num_clauses; ++i) {
693                 clause = &header->clauses [i];
694                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
695                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
696                         if (clause->flags == type)
697                                 res = g_list_append (res, clause);
698                 }
699         }
700         return res;
701 }
702
703 static void
704 mono_create_spvar_for_region (MonoCompile *cfg, int region)
705 {
706         MonoInst *var;
707
708         var = (MonoInst *)g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
709         if (var)
710                 return;
711
712         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
713         /* prevent it from being register allocated */
714         var->flags |= MONO_INST_VOLATILE;
715
716         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
717 }
718
719 MonoInst *
720 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
721 {
722         return (MonoInst *)g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
723 }
724
725 static MonoInst*
726 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
727 {
728         MonoInst *var;
729
730         var = (MonoInst *)g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
731         if (var)
732                 return var;
733
734         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
735         /* prevent it from being register allocated */
736         var->flags |= MONO_INST_VOLATILE;
737
738         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
739
740         return var;
741 }
742
743 /*
744  * Returns the type used in the eval stack when @type is loaded.
745  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
746  */
747 void
748 type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
749 {
750         MonoClass *klass;
751
752         type = mini_get_underlying_type (type);
753         inst->klass = klass = mono_class_from_mono_type (type);
754         if (type->byref) {
755                 inst->type = STACK_MP;
756                 return;
757         }
758
759 handle_enum:
760         switch (type->type) {
761         case MONO_TYPE_VOID:
762                 inst->type = STACK_INV;
763                 return;
764         case MONO_TYPE_I1:
765         case MONO_TYPE_U1:
766         case MONO_TYPE_I2:
767         case MONO_TYPE_U2:
768         case MONO_TYPE_I4:
769         case MONO_TYPE_U4:
770                 inst->type = STACK_I4;
771                 return;
772         case MONO_TYPE_I:
773         case MONO_TYPE_U:
774         case MONO_TYPE_PTR:
775         case MONO_TYPE_FNPTR:
776                 inst->type = STACK_PTR;
777                 return;
778         case MONO_TYPE_CLASS:
779         case MONO_TYPE_STRING:
780         case MONO_TYPE_OBJECT:
781         case MONO_TYPE_SZARRAY:
782         case MONO_TYPE_ARRAY:    
783                 inst->type = STACK_OBJ;
784                 return;
785         case MONO_TYPE_I8:
786         case MONO_TYPE_U8:
787                 inst->type = STACK_I8;
788                 return;
789         case MONO_TYPE_R4:
790                 inst->type = cfg->r4_stack_type;
791                 break;
792         case MONO_TYPE_R8:
793                 inst->type = STACK_R8;
794                 return;
795         case MONO_TYPE_VALUETYPE:
796                 if (type->data.klass->enumtype) {
797                         type = mono_class_enum_basetype (type->data.klass);
798                         goto handle_enum;
799                 } else {
800                         inst->klass = klass;
801                         inst->type = STACK_VTYPE;
802                         return;
803                 }
804         case MONO_TYPE_TYPEDBYREF:
805                 inst->klass = mono_defaults.typed_reference_class;
806                 inst->type = STACK_VTYPE;
807                 return;
808         case MONO_TYPE_GENERICINST:
809                 type = &type->data.generic_class->container_class->byval_arg;
810                 goto handle_enum;
811         case MONO_TYPE_VAR:
812         case MONO_TYPE_MVAR:
813                 g_assert (cfg->gshared);
814                 if (mini_is_gsharedvt_type (type)) {
815                         g_assert (cfg->gsharedvt);
816                         inst->type = STACK_VTYPE;
817                 } else {
818                         type_to_eval_stack_type (cfg, mini_get_underlying_type (type), inst);
819                 }
820                 return;
821         default:
822                 g_error ("unknown type 0x%02x in eval stack type", type->type);
823         }
824 }
825
826 /*
827  * The following tables are used to quickly validate the IL code in type_from_op ().
828  */
829 static const char
830 bin_num_table [STACK_MAX] [STACK_MAX] = {
831         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
832         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
833         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
834         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
835         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV, STACK_R8},
836         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
837         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
838         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
839         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4}
840 };
841
842 static const char 
843 neg_table [] = {
844         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4
845 };
846
847 /* reduce the size of this table */
848 static const char
849 bin_int_table [STACK_MAX] [STACK_MAX] = {
850         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
851         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
852         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
853         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
854         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
855         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
856         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
857         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
858 };
859
860 static const char
861 bin_comp_table [STACK_MAX] [STACK_MAX] = {
862 /*      Inv i  L  p  F  &  O  vt r4 */
863         {0},
864         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
865         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
866         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
867         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* F, R8 */
868         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
869         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
870         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
871         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* r, r4 */
872 };
873
874 /* reduce the size of this table */
875 static const char
876 shift_table [STACK_MAX] [STACK_MAX] = {
877         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
878         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
879         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
880         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
881         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
882         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
883         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
884         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
885 };
886
887 /*
888  * Tables to map from the non-specific opcode to the matching
889  * type-specific opcode.
890  */
891 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
892 static const guint16
893 binops_op_map [STACK_MAX] = {
894         0, OP_IADD-CEE_ADD, OP_LADD-CEE_ADD, OP_PADD-CEE_ADD, OP_FADD-CEE_ADD, OP_PADD-CEE_ADD, 0, 0, OP_RADD-CEE_ADD
895 };
896
897 /* handles from CEE_NEG to CEE_CONV_U8 */
898 static const guint16
899 unops_op_map [STACK_MAX] = {
900         0, OP_INEG-CEE_NEG, OP_LNEG-CEE_NEG, OP_PNEG-CEE_NEG, OP_FNEG-CEE_NEG, OP_PNEG-CEE_NEG, 0, 0, OP_RNEG-CEE_NEG
901 };
902
903 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
904 static const guint16
905 ovfops_op_map [STACK_MAX] = {
906         0, OP_ICONV_TO_U2-CEE_CONV_U2, OP_LCONV_TO_U2-CEE_CONV_U2, OP_PCONV_TO_U2-CEE_CONV_U2, OP_FCONV_TO_U2-CEE_CONV_U2, OP_PCONV_TO_U2-CEE_CONV_U2, OP_PCONV_TO_U2-CEE_CONV_U2, 0, OP_RCONV_TO_U2-CEE_CONV_U2
907 };
908
909 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
910 static const guint16
911 ovf2ops_op_map [STACK_MAX] = {
912         0, OP_ICONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, OP_LCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, OP_PCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, OP_FCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, OP_PCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, 0, 0, OP_RCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN
913 };
914
915 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
916 static const guint16
917 ovf3ops_op_map [STACK_MAX] = {
918         0, OP_ICONV_TO_OVF_I1-CEE_CONV_OVF_I1, OP_LCONV_TO_OVF_I1-CEE_CONV_OVF_I1, OP_PCONV_TO_OVF_I1-CEE_CONV_OVF_I1, OP_FCONV_TO_OVF_I1-CEE_CONV_OVF_I1, OP_PCONV_TO_OVF_I1-CEE_CONV_OVF_I1, 0, 0, OP_RCONV_TO_OVF_I1-CEE_CONV_OVF_I1
919 };
920
921 /* handles from CEE_BEQ to CEE_BLT_UN */
922 static const guint16
923 beqops_op_map [STACK_MAX] = {
924         0, OP_IBEQ-CEE_BEQ, OP_LBEQ-CEE_BEQ, OP_PBEQ-CEE_BEQ, OP_FBEQ-CEE_BEQ, OP_PBEQ-CEE_BEQ, OP_PBEQ-CEE_BEQ, 0, OP_FBEQ-CEE_BEQ
925 };
926
927 /* handles from CEE_CEQ to CEE_CLT_UN */
928 static const guint16
929 ceqops_op_map [STACK_MAX] = {
930         0, OP_ICEQ-OP_CEQ, OP_LCEQ-OP_CEQ, OP_PCEQ-OP_CEQ, OP_FCEQ-OP_CEQ, OP_PCEQ-OP_CEQ, OP_PCEQ-OP_CEQ, 0, OP_RCEQ-OP_CEQ
931 };
932
933 /*
934  * Sets ins->type (the type on the eval stack) according to the
935  * type of the opcode and the arguments to it.
936  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
937  *
938  * FIXME: this function sets ins->type unconditionally in some cases, but
939  * it should set it to invalid for some types (a conv.x on an object)
940  */
941 static void
942 type_from_op (MonoCompile *cfg, MonoInst *ins, MonoInst *src1, MonoInst *src2)
943 {
944         switch (ins->opcode) {
945         /* binops */
946         case CEE_ADD:
947         case CEE_SUB:
948         case CEE_MUL:
949         case CEE_DIV:
950         case CEE_REM:
951                 /* FIXME: check unverifiable args for STACK_MP */
952                 ins->type = bin_num_table [src1->type] [src2->type];
953                 ins->opcode += binops_op_map [ins->type];
954                 break;
955         case CEE_DIV_UN:
956         case CEE_REM_UN:
957         case CEE_AND:
958         case CEE_OR:
959         case CEE_XOR:
960                 ins->type = bin_int_table [src1->type] [src2->type];
961                 ins->opcode += binops_op_map [ins->type];
962                 break;
963         case CEE_SHL:
964         case CEE_SHR:
965         case CEE_SHR_UN:
966                 ins->type = shift_table [src1->type] [src2->type];
967                 ins->opcode += binops_op_map [ins->type];
968                 break;
969         case OP_COMPARE:
970         case OP_LCOMPARE:
971         case OP_ICOMPARE:
972                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
973                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
974                         ins->opcode = OP_LCOMPARE;
975                 else if (src1->type == STACK_R4)
976                         ins->opcode = OP_RCOMPARE;
977                 else if (src1->type == STACK_R8)
978                         ins->opcode = OP_FCOMPARE;
979                 else
980                         ins->opcode = OP_ICOMPARE;
981                 break;
982         case OP_ICOMPARE_IMM:
983                 ins->type = bin_comp_table [src1->type] [src1->type] ? STACK_I4 : STACK_INV;
984                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
985                         ins->opcode = OP_LCOMPARE_IMM;          
986                 break;
987         case CEE_BEQ:
988         case CEE_BGE:
989         case CEE_BGT:
990         case CEE_BLE:
991         case CEE_BLT:
992         case CEE_BNE_UN:
993         case CEE_BGE_UN:
994         case CEE_BGT_UN:
995         case CEE_BLE_UN:
996         case CEE_BLT_UN:
997                 ins->opcode += beqops_op_map [src1->type];
998                 break;
999         case OP_CEQ:
1000                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
1001                 ins->opcode += ceqops_op_map [src1->type];
1002                 break;
1003         case OP_CGT:
1004         case OP_CGT_UN:
1005         case OP_CLT:
1006         case OP_CLT_UN:
1007                 ins->type = (bin_comp_table [src1->type] [src2->type] & 1) ? STACK_I4: STACK_INV;
1008                 ins->opcode += ceqops_op_map [src1->type];
1009                 break;
1010         /* unops */
1011         case CEE_NEG:
1012                 ins->type = neg_table [src1->type];
1013                 ins->opcode += unops_op_map [ins->type];
1014                 break;
1015         case CEE_NOT:
1016                 if (src1->type >= STACK_I4 && src1->type <= STACK_PTR)
1017                         ins->type = src1->type;
1018                 else
1019                         ins->type = STACK_INV;
1020                 ins->opcode += unops_op_map [ins->type];
1021                 break;
1022         case CEE_CONV_I1:
1023         case CEE_CONV_I2:
1024         case CEE_CONV_I4:
1025         case CEE_CONV_U4:
1026                 ins->type = STACK_I4;
1027                 ins->opcode += unops_op_map [src1->type];
1028                 break;
1029         case CEE_CONV_R_UN:
1030                 ins->type = STACK_R8;
1031                 switch (src1->type) {
1032                 case STACK_I4:
1033                 case STACK_PTR:
1034                         ins->opcode = OP_ICONV_TO_R_UN;
1035                         break;
1036                 case STACK_I8:
1037                         ins->opcode = OP_LCONV_TO_R_UN; 
1038                         break;
1039                 }
1040                 break;
1041         case CEE_CONV_OVF_I1:
1042         case CEE_CONV_OVF_U1:
1043         case CEE_CONV_OVF_I2:
1044         case CEE_CONV_OVF_U2:
1045         case CEE_CONV_OVF_I4:
1046         case CEE_CONV_OVF_U4:
1047                 ins->type = STACK_I4;
1048                 ins->opcode += ovf3ops_op_map [src1->type];
1049                 break;
1050         case CEE_CONV_OVF_I_UN:
1051         case CEE_CONV_OVF_U_UN:
1052                 ins->type = STACK_PTR;
1053                 ins->opcode += ovf2ops_op_map [src1->type];
1054                 break;
1055         case CEE_CONV_OVF_I1_UN:
1056         case CEE_CONV_OVF_I2_UN:
1057         case CEE_CONV_OVF_I4_UN:
1058         case CEE_CONV_OVF_U1_UN:
1059         case CEE_CONV_OVF_U2_UN:
1060         case CEE_CONV_OVF_U4_UN:
1061                 ins->type = STACK_I4;
1062                 ins->opcode += ovf2ops_op_map [src1->type];
1063                 break;
1064         case CEE_CONV_U:
1065                 ins->type = STACK_PTR;
1066                 switch (src1->type) {
1067                 case STACK_I4:
1068                         ins->opcode = OP_ICONV_TO_U;
1069                         break;
1070                 case STACK_PTR:
1071                 case STACK_MP:
1072 #if SIZEOF_VOID_P == 8
1073                         ins->opcode = OP_LCONV_TO_U;
1074 #else
1075                         ins->opcode = OP_MOVE;
1076 #endif
1077                         break;
1078                 case STACK_I8:
1079                         ins->opcode = OP_LCONV_TO_U;
1080                         break;
1081                 case STACK_R8:
1082                         ins->opcode = OP_FCONV_TO_U;
1083                         break;
1084                 }
1085                 break;
1086         case CEE_CONV_I8:
1087         case CEE_CONV_U8:
1088                 ins->type = STACK_I8;
1089                 ins->opcode += unops_op_map [src1->type];
1090                 break;
1091         case CEE_CONV_OVF_I8:
1092         case CEE_CONV_OVF_U8:
1093                 ins->type = STACK_I8;
1094                 ins->opcode += ovf3ops_op_map [src1->type];
1095                 break;
1096         case CEE_CONV_OVF_U8_UN:
1097         case CEE_CONV_OVF_I8_UN:
1098                 ins->type = STACK_I8;
1099                 ins->opcode += ovf2ops_op_map [src1->type];
1100                 break;
1101         case CEE_CONV_R4:
1102                 ins->type = cfg->r4_stack_type;
1103                 ins->opcode += unops_op_map [src1->type];
1104                 break;
1105         case CEE_CONV_R8:
1106                 ins->type = STACK_R8;
1107                 ins->opcode += unops_op_map [src1->type];
1108                 break;
1109         case OP_CKFINITE:
1110                 ins->type = STACK_R8;           
1111                 break;
1112         case CEE_CONV_U2:
1113         case CEE_CONV_U1:
1114                 ins->type = STACK_I4;
1115                 ins->opcode += ovfops_op_map [src1->type];
1116                 break;
1117         case CEE_CONV_I:
1118         case CEE_CONV_OVF_I:
1119         case CEE_CONV_OVF_U:
1120                 ins->type = STACK_PTR;
1121                 ins->opcode += ovfops_op_map [src1->type];
1122                 break;
1123         case CEE_ADD_OVF:
1124         case CEE_ADD_OVF_UN:
1125         case CEE_MUL_OVF:
1126         case CEE_MUL_OVF_UN:
1127         case CEE_SUB_OVF:
1128         case CEE_SUB_OVF_UN:
1129                 ins->type = bin_num_table [src1->type] [src2->type];
1130                 ins->opcode += ovfops_op_map [src1->type];
1131                 if (ins->type == STACK_R8)
1132                         ins->type = STACK_INV;
1133                 break;
1134         case OP_LOAD_MEMBASE:
1135                 ins->type = STACK_PTR;
1136                 break;
1137         case OP_LOADI1_MEMBASE:
1138         case OP_LOADU1_MEMBASE:
1139         case OP_LOADI2_MEMBASE:
1140         case OP_LOADU2_MEMBASE:
1141         case OP_LOADI4_MEMBASE:
1142         case OP_LOADU4_MEMBASE:
1143                 ins->type = STACK_PTR;
1144                 break;
1145         case OP_LOADI8_MEMBASE:
1146                 ins->type = STACK_I8;
1147                 break;
1148         case OP_LOADR4_MEMBASE:
1149                 ins->type = cfg->r4_stack_type;
1150                 break;
1151         case OP_LOADR8_MEMBASE:
1152                 ins->type = STACK_R8;
1153                 break;
1154         default:
1155                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1156                 break;
1157         }
1158
1159         if (ins->type == STACK_MP)
1160                 ins->klass = mono_defaults.object_class;
1161 }
1162
1163 static const char 
1164 ldind_type [] = {
1165         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
1166 };
1167
1168 #if 0
1169
1170 static const char
1171 param_table [STACK_MAX] [STACK_MAX] = {
1172         {0},
1173 };
1174
1175 static int
1176 check_values_to_signature (MonoInst *args, MonoType *this_ins, MonoMethodSignature *sig)
1177 {
1178         int i;
1179
1180         if (sig->hasthis) {
1181                 switch (args->type) {
1182                 case STACK_I4:
1183                 case STACK_I8:
1184                 case STACK_R8:
1185                 case STACK_VTYPE:
1186                 case STACK_INV:
1187                         return 0;
1188                 }
1189                 args++;
1190         }
1191         for (i = 0; i < sig->param_count; ++i) {
1192                 switch (args [i].type) {
1193                 case STACK_INV:
1194                         return 0;
1195                 case STACK_MP:
1196                         if (!sig->params [i]->byref)
1197                                 return 0;
1198                         continue;
1199                 case STACK_OBJ:
1200                         if (sig->params [i]->byref)
1201                                 return 0;
1202                         switch (sig->params [i]->type) {
1203                         case MONO_TYPE_CLASS:
1204                         case MONO_TYPE_STRING:
1205                         case MONO_TYPE_OBJECT:
1206                         case MONO_TYPE_SZARRAY:
1207                         case MONO_TYPE_ARRAY:
1208                                 break;
1209                         default:
1210                                 return 0;
1211                         }
1212                         continue;
1213                 case STACK_R8:
1214                         if (sig->params [i]->byref)
1215                                 return 0;
1216                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1217                                 return 0;
1218                         continue;
1219                 case STACK_PTR:
1220                 case STACK_I4:
1221                 case STACK_I8:
1222                 case STACK_VTYPE:
1223                         break;
1224                 }
1225                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1226                         return 0;*/
1227         }
1228         return 1;
1229 }
1230 #endif
1231
1232 /*
1233  * When we need a pointer to the current domain many times in a method, we
1234  * call mono_domain_get() once and we store the result in a local variable.
1235  * This function returns the variable that represents the MonoDomain*.
1236  */
1237 inline static MonoInst *
1238 mono_get_domainvar (MonoCompile *cfg)
1239 {
1240         if (!cfg->domainvar)
1241                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1242         return cfg->domainvar;
1243 }
1244
1245 /*
1246  * The got_var contains the address of the Global Offset Table when AOT 
1247  * compiling.
1248  */
1249 MonoInst *
1250 mono_get_got_var (MonoCompile *cfg)
1251 {
1252         if (!cfg->compile_aot || !cfg->backend->need_got_var)
1253                 return NULL;
1254         if (!cfg->got_var) {
1255                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1256         }
1257         return cfg->got_var;
1258 }
1259
1260 static MonoInst *
1261 mono_get_vtable_var (MonoCompile *cfg)
1262 {
1263         g_assert (cfg->gshared);
1264
1265         if (!cfg->rgctx_var) {
1266                 cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1267                 /* force the var to be stack allocated */
1268                 cfg->rgctx_var->flags |= MONO_INST_VOLATILE;
1269         }
1270
1271         return cfg->rgctx_var;
1272 }
1273
1274 static MonoType*
1275 type_from_stack_type (MonoInst *ins) {
1276         switch (ins->type) {
1277         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1278         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1279         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1280         case STACK_R4: return &mono_defaults.single_class->byval_arg;
1281         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1282         case STACK_MP:
1283                 return &ins->klass->this_arg;
1284         case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1285         case STACK_VTYPE: return &ins->klass->byval_arg;
1286         default:
1287                 g_error ("stack type %d to monotype not handled\n", ins->type);
1288         }
1289         return NULL;
1290 }
1291
1292 static G_GNUC_UNUSED int
1293 type_to_stack_type (MonoCompile *cfg, MonoType *t)
1294 {
1295         t = mono_type_get_underlying_type (t);
1296         switch (t->type) {
1297         case MONO_TYPE_I1:
1298         case MONO_TYPE_U1:
1299         case MONO_TYPE_I2:
1300         case MONO_TYPE_U2:
1301         case MONO_TYPE_I4:
1302         case MONO_TYPE_U4:
1303                 return STACK_I4;
1304         case MONO_TYPE_I:
1305         case MONO_TYPE_U:
1306         case MONO_TYPE_PTR:
1307         case MONO_TYPE_FNPTR:
1308                 return STACK_PTR;
1309         case MONO_TYPE_CLASS:
1310         case MONO_TYPE_STRING:
1311         case MONO_TYPE_OBJECT:
1312         case MONO_TYPE_SZARRAY:
1313         case MONO_TYPE_ARRAY:    
1314                 return STACK_OBJ;
1315         case MONO_TYPE_I8:
1316         case MONO_TYPE_U8:
1317                 return STACK_I8;
1318         case MONO_TYPE_R4:
1319                 return cfg->r4_stack_type;
1320         case MONO_TYPE_R8:
1321                 return STACK_R8;
1322         case MONO_TYPE_VALUETYPE:
1323         case MONO_TYPE_TYPEDBYREF:
1324                 return STACK_VTYPE;
1325         case MONO_TYPE_GENERICINST:
1326                 if (mono_type_generic_inst_is_valuetype (t))
1327                         return STACK_VTYPE;
1328                 else
1329                         return STACK_OBJ;
1330                 break;
1331         default:
1332                 g_assert_not_reached ();
1333         }
1334
1335         return -1;
1336 }
1337
1338 static MonoClass*
1339 array_access_to_klass (int opcode)
1340 {
1341         switch (opcode) {
1342         case CEE_LDELEM_U1:
1343                 return mono_defaults.byte_class;
1344         case CEE_LDELEM_U2:
1345                 return mono_defaults.uint16_class;
1346         case CEE_LDELEM_I:
1347         case CEE_STELEM_I:
1348                 return mono_defaults.int_class;
1349         case CEE_LDELEM_I1:
1350         case CEE_STELEM_I1:
1351                 return mono_defaults.sbyte_class;
1352         case CEE_LDELEM_I2:
1353         case CEE_STELEM_I2:
1354                 return mono_defaults.int16_class;
1355         case CEE_LDELEM_I4:
1356         case CEE_STELEM_I4:
1357                 return mono_defaults.int32_class;
1358         case CEE_LDELEM_U4:
1359                 return mono_defaults.uint32_class;
1360         case CEE_LDELEM_I8:
1361         case CEE_STELEM_I8:
1362                 return mono_defaults.int64_class;
1363         case CEE_LDELEM_R4:
1364         case CEE_STELEM_R4:
1365                 return mono_defaults.single_class;
1366         case CEE_LDELEM_R8:
1367         case CEE_STELEM_R8:
1368                 return mono_defaults.double_class;
1369         case CEE_LDELEM_REF:
1370         case CEE_STELEM_REF:
1371                 return mono_defaults.object_class;
1372         default:
1373                 g_assert_not_reached ();
1374         }
1375         return NULL;
1376 }
1377
1378 /*
1379  * We try to share variables when possible
1380  */
1381 static MonoInst *
1382 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1383 {
1384         MonoInst *res;
1385         int pos, vnum;
1386
1387         /* inlining can result in deeper stacks */ 
1388         if (slot >= cfg->header->max_stack)
1389                 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1390
1391         pos = ins->type - 1 + slot * STACK_MAX;
1392
1393         switch (ins->type) {
1394         case STACK_I4:
1395         case STACK_I8:
1396         case STACK_R8:
1397         case STACK_PTR:
1398         case STACK_MP:
1399         case STACK_OBJ:
1400                 if ((vnum = cfg->intvars [pos]))
1401                         return cfg->varinfo [vnum];
1402                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1403                 cfg->intvars [pos] = res->inst_c0;
1404                 break;
1405         default:
1406                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1407         }
1408         return res;
1409 }
1410
1411 static void
1412 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
1413 {
1414         /* 
1415          * Don't use this if a generic_context is set, since that means AOT can't
1416          * look up the method using just the image+token.
1417          * table == 0 means this is a reference made from a wrapper.
1418          */
1419         if (cfg->compile_aot && !cfg->generic_context && (mono_metadata_token_table (token) > 0)) {
1420                 MonoJumpInfoToken *jump_info_token = (MonoJumpInfoToken *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
1421                 jump_info_token->image = image;
1422                 jump_info_token->token = token;
1423                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
1424         }
1425 }
1426
1427 /*
1428  * This function is called to handle items that are left on the evaluation stack
1429  * at basic block boundaries. What happens is that we save the values to local variables
1430  * and we reload them later when first entering the target basic block (with the
1431  * handle_loaded_temps () function).
1432  * A single joint point will use the same variables (stored in the array bb->out_stack or
1433  * bb->in_stack, if the basic block is before or after the joint point).
1434  *
1435  * This function needs to be called _before_ emitting the last instruction of
1436  * the bb (i.e. before emitting a branch).
1437  * If the stack merge fails at a join point, cfg->unverifiable is set.
1438  */
1439 static void
1440 handle_stack_args (MonoCompile *cfg, MonoInst **sp, int count)
1441 {
1442         int i, bindex;
1443         MonoBasicBlock *bb = cfg->cbb;
1444         MonoBasicBlock *outb;
1445         MonoInst *inst, **locals;
1446         gboolean found;
1447
1448         if (!count)
1449                 return;
1450         if (cfg->verbose_level > 3)
1451                 printf ("%d item(s) on exit from B%d\n", count, bb->block_num);
1452         if (!bb->out_scount) {
1453                 bb->out_scount = count;
1454                 //printf ("bblock %d has out:", bb->block_num);
1455                 found = FALSE;
1456                 for (i = 0; i < bb->out_count; ++i) {
1457                         outb = bb->out_bb [i];
1458                         /* exception handlers are linked, but they should not be considered for stack args */
1459                         if (outb->flags & BB_EXCEPTION_HANDLER)
1460                                 continue;
1461                         //printf (" %d", outb->block_num);
1462                         if (outb->in_stack) {
1463                                 found = TRUE;
1464                                 bb->out_stack = outb->in_stack;
1465                                 break;
1466                         }
1467                 }
1468                 //printf ("\n");
1469                 if (!found) {
1470                         bb->out_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1471                         for (i = 0; i < count; ++i) {
1472                                 /* 
1473                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
1474                                  * stack slot and if they are of the same type.
1475                                  * This won't cause conflicts since if 'local' is used to 
1476                                  * store one of the values in the in_stack of a bblock, then
1477                                  * the same variable will be used for the same outgoing stack 
1478                                  * slot as well. 
1479                                  * This doesn't work when inlining methods, since the bblocks
1480                                  * in the inlined methods do not inherit their in_stack from
1481                                  * the bblock they are inlined to. See bug #58863 for an
1482                                  * example.
1483                                  */
1484                                 if (cfg->inlined_method)
1485                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1486                                 else
1487                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1488                         }
1489                 }
1490         }
1491
1492         for (i = 0; i < bb->out_count; ++i) {
1493                 outb = bb->out_bb [i];
1494                 /* exception handlers are linked, but they should not be considered for stack args */
1495                 if (outb->flags & BB_EXCEPTION_HANDLER)
1496                         continue;
1497                 if (outb->in_scount) {
1498                         if (outb->in_scount != bb->out_scount) {
1499                                 cfg->unverifiable = TRUE;
1500                                 return;
1501                         }
1502                         continue; /* check they are the same locals */
1503                 }
1504                 outb->in_scount = count;
1505                 outb->in_stack = bb->out_stack;
1506         }
1507
1508         locals = bb->out_stack;
1509         cfg->cbb = bb;
1510         for (i = 0; i < count; ++i) {
1511                 EMIT_NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1512                 inst->cil_code = sp [i]->cil_code;
1513                 sp [i] = locals [i];
1514                 if (cfg->verbose_level > 3)
1515                         printf ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
1516         }
1517
1518         /*
1519          * It is possible that the out bblocks already have in_stack assigned, and
1520          * the in_stacks differ. In this case, we will store to all the different 
1521          * in_stacks.
1522          */
1523
1524         found = TRUE;
1525         bindex = 0;
1526         while (found) {
1527                 /* Find a bblock which has a different in_stack */
1528                 found = FALSE;
1529                 while (bindex < bb->out_count) {
1530                         outb = bb->out_bb [bindex];
1531                         /* exception handlers are linked, but they should not be considered for stack args */
1532                         if (outb->flags & BB_EXCEPTION_HANDLER) {
1533                                 bindex++;
1534                                 continue;
1535                         }
1536                         if (outb->in_stack != locals) {
1537                                 for (i = 0; i < count; ++i) {
1538                                         EMIT_NEW_TEMPSTORE (cfg, inst, outb->in_stack [i]->inst_c0, sp [i]);
1539                                         inst->cil_code = sp [i]->cil_code;
1540                                         sp [i] = locals [i];
1541                                         if (cfg->verbose_level > 3)
1542                                                 printf ("storing %d to temp %d\n", i, (int)outb->in_stack [i]->inst_c0);
1543                                 }
1544                                 locals = outb->in_stack;
1545                                 found = TRUE;
1546                                 break;
1547                         }
1548                         bindex ++;
1549                 }
1550         }
1551 }
1552
1553 static MonoInst*
1554 emit_runtime_constant (MonoCompile *cfg, MonoJumpInfoType patch_type, gpointer data)
1555 {
1556         MonoInst *ins;
1557
1558         if (cfg->compile_aot) {
1559                 EMIT_NEW_AOTCONST (cfg, ins, patch_type, data);
1560         } else {
1561                 MonoJumpInfo ji;
1562                 gpointer target;
1563                 MonoError error;
1564
1565                 ji.type = patch_type;
1566                 ji.data.target = data;
1567                 target = mono_resolve_patch_target (NULL, cfg->domain, NULL, &ji, FALSE, &error);
1568                 mono_error_assert_ok (&error);
1569
1570                 EMIT_NEW_PCONST (cfg, ins, target);
1571         }
1572         return ins;
1573 }
1574
1575 MonoInst*
1576 mini_emit_runtime_constant (MonoCompile *cfg, MonoJumpInfoType patch_type, gpointer data)
1577 {
1578         return emit_runtime_constant (cfg, patch_type, data);
1579 }
1580
1581 static void 
1582 mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
1583 {
1584         int val_reg;
1585
1586         g_assert (val == 0);
1587
1588         if (align == 0)
1589                 align = 4;
1590
1591         if ((size <= SIZEOF_REGISTER) && (size <= align)) {
1592                 switch (size) {
1593                 case 1:
1594                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, destreg, offset, val);
1595                         return;
1596                 case 2:
1597                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI2_MEMBASE_IMM, destreg, offset, val);
1598                         return;
1599                 case 4:
1600                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, destreg, offset, val);
1601                         return;
1602 #if SIZEOF_REGISTER == 8
1603                 case 8:
1604                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI8_MEMBASE_IMM, destreg, offset, val);
1605                         return;
1606 #endif
1607                 }
1608         }
1609
1610         val_reg = alloc_preg (cfg);
1611
1612         if (SIZEOF_REGISTER == 8)
1613                 MONO_EMIT_NEW_I8CONST (cfg, val_reg, val);
1614         else
1615                 MONO_EMIT_NEW_ICONST (cfg, val_reg, val);
1616
1617         if (align < 4) {
1618                 /* This could be optimized further if neccesary */
1619                 while (size >= 1) {
1620                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1621                         offset += 1;
1622                         size -= 1;
1623                 }
1624                 return;
1625         }       
1626
1627         if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
1628                 if (offset % 8) {
1629                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1630                         offset += 4;
1631                         size -= 4;
1632                 }
1633                 while (size >= 8) {
1634                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, offset, val_reg);
1635                         offset += 8;
1636                         size -= 8;
1637                 }
1638         }       
1639
1640         while (size >= 4) {
1641                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1642                 offset += 4;
1643                 size -= 4;
1644         }
1645         while (size >= 2) {
1646                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg);
1647                 offset += 2;
1648                 size -= 2;
1649         }
1650         while (size >= 1) {
1651                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1652                 offset += 1;
1653                 size -= 1;
1654         }
1655 }
1656
1657 void 
1658 mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
1659 {
1660         int cur_reg;
1661
1662         if (align == 0)
1663                 align = 4;
1664
1665         /*FIXME arbitrary hack to avoid unbound code expansion.*/
1666         g_assert (size < 10000);
1667
1668         if (align < 4) {
1669                 /* This could be optimized further if neccesary */
1670                 while (size >= 1) {
1671                         cur_reg = alloc_preg (cfg);
1672                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1673                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1674                         doffset += 1;
1675                         soffset += 1;
1676                         size -= 1;
1677                 }
1678         }
1679
1680         if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
1681                 while (size >= 8) {
1682                         cur_reg = alloc_preg (cfg);
1683                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI8_MEMBASE, cur_reg, srcreg, soffset);
1684                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, doffset, cur_reg);
1685                         doffset += 8;
1686                         soffset += 8;
1687                         size -= 8;
1688                 }
1689         }       
1690
1691         while (size >= 4) {
1692                 cur_reg = alloc_preg (cfg);
1693                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, cur_reg, srcreg, soffset);
1694                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, doffset, cur_reg);
1695                 doffset += 4;
1696                 soffset += 4;
1697                 size -= 4;
1698         }
1699         while (size >= 2) {
1700                 cur_reg = alloc_preg (cfg);
1701                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, cur_reg, srcreg, soffset);
1702                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, doffset, cur_reg);
1703                 doffset += 2;
1704                 soffset += 2;
1705                 size -= 2;
1706         }
1707         while (size >= 1) {
1708                 cur_reg = alloc_preg (cfg);
1709                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1710                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1711                 doffset += 1;
1712                 soffset += 1;
1713                 size -= 1;
1714         }
1715 }
1716
1717 static void
1718 emit_tls_set (MonoCompile *cfg, int sreg1, MonoTlsKey tls_key)
1719 {
1720         MonoInst *ins, *c;
1721
1722         if (cfg->compile_aot) {
1723                 EMIT_NEW_TLS_OFFSETCONST (cfg, c, tls_key);
1724                 MONO_INST_NEW (cfg, ins, OP_TLS_SET_REG);
1725                 ins->sreg1 = sreg1;
1726                 ins->sreg2 = c->dreg;
1727                 MONO_ADD_INS (cfg->cbb, ins);
1728         } else {
1729                 MONO_INST_NEW (cfg, ins, OP_TLS_SET);
1730                 ins->sreg1 = sreg1;
1731                 ins->inst_offset = mini_get_tls_offset (tls_key);
1732                 MONO_ADD_INS (cfg->cbb, ins);
1733         }
1734 }
1735
1736 /*
1737  * emit_push_lmf:
1738  *
1739  *   Emit IR to push the current LMF onto the LMF stack.
1740  */
1741 static void
1742 emit_push_lmf (MonoCompile *cfg)
1743 {
1744         /*
1745          * Emit IR to push the LMF:
1746          * lmf_addr = <lmf_addr from tls>
1747          * lmf->lmf_addr = lmf_addr
1748          * lmf->prev_lmf = *lmf_addr
1749          * *lmf_addr = lmf
1750          */
1751         int lmf_reg, prev_lmf_reg;
1752         MonoInst *ins, *lmf_ins;
1753
1754         if (!cfg->lmf_ir)
1755                 return;
1756
1757         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
1758                 /* Load current lmf */
1759                 lmf_ins = mono_get_lmf_intrinsic (cfg);
1760                 g_assert (lmf_ins);
1761                 MONO_ADD_INS (cfg->cbb, lmf_ins);
1762                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
1763                 lmf_reg = ins->dreg;
1764                 /* Save previous_lmf */
1765                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), lmf_ins->dreg);
1766                 /* Set new LMF */
1767                 emit_tls_set (cfg, lmf_reg, TLS_KEY_LMF);
1768         } else {
1769                 /*
1770                  * Store lmf_addr in a variable, so it can be allocated to a global register.
1771                  */
1772                 if (!cfg->lmf_addr_var)
1773                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1774
1775 #ifdef HOST_WIN32
1776                 ins = mono_get_jit_tls_intrinsic (cfg);
1777                 if (ins) {
1778                         int jit_tls_dreg = ins->dreg;
1779
1780                         MONO_ADD_INS (cfg->cbb, ins);
1781                         lmf_reg = alloc_preg (cfg);
1782                         EMIT_NEW_BIALU_IMM (cfg, lmf_ins, OP_PADD_IMM, lmf_reg, jit_tls_dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
1783                 } else {
1784                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
1785                 }
1786 #else
1787                 lmf_ins = mono_get_lmf_addr_intrinsic (cfg);
1788                 if (lmf_ins) {
1789                         MONO_ADD_INS (cfg->cbb, lmf_ins);
1790                 } else {
1791 #ifdef TARGET_IOS
1792                         MonoInst *args [16], *jit_tls_ins, *ins;
1793
1794                         /* Inline mono_get_lmf_addr () */
1795                         /* jit_tls = pthread_getspecific (mono_jit_tls_id); lmf_addr = &jit_tls->lmf; */
1796
1797                         /* Load mono_jit_tls_id */
1798                         if (cfg->compile_aot)
1799                                 EMIT_NEW_AOTCONST (cfg, args [0], MONO_PATCH_INFO_JIT_TLS_ID, NULL);
1800                         else
1801                                 EMIT_NEW_ICONST (cfg, args [0], mono_jit_tls_id);
1802                         /* call pthread_getspecific () */
1803                         jit_tls_ins = mono_emit_jit_icall (cfg, pthread_getspecific, args);
1804                         /* lmf_addr = &jit_tls->lmf */
1805                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, cfg->lmf_addr_var->dreg, jit_tls_ins->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
1806                         lmf_ins = ins;
1807 #else
1808                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
1809 #endif
1810                 }
1811 #endif
1812                 lmf_ins->dreg = cfg->lmf_addr_var->dreg;
1813
1814                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
1815                 lmf_reg = ins->dreg;
1816
1817                 prev_lmf_reg = alloc_preg (cfg);
1818                 /* Save previous_lmf */
1819                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, cfg->lmf_addr_var->dreg, 0);
1820                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), prev_lmf_reg);
1821                 /* Set new lmf */
1822                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, cfg->lmf_addr_var->dreg, 0, lmf_reg);
1823         }
1824 }
1825
1826 /*
1827  * emit_pop_lmf:
1828  *
1829  *   Emit IR to pop the current LMF from the LMF stack.
1830  */
1831 static void
1832 emit_pop_lmf (MonoCompile *cfg)
1833 {
1834         int lmf_reg, lmf_addr_reg, prev_lmf_reg;
1835         MonoInst *ins;
1836
1837         if (!cfg->lmf_ir)
1838                 return;
1839
1840         EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
1841         lmf_reg = ins->dreg;
1842
1843         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
1844                 /* Load previous_lmf */
1845                 prev_lmf_reg = alloc_preg (cfg);
1846                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
1847                 /* Set new LMF */
1848                 emit_tls_set (cfg, prev_lmf_reg, TLS_KEY_LMF);
1849         } else {
1850                 /*
1851                  * Emit IR to pop the LMF:
1852                  * *(lmf->lmf_addr) = lmf->prev_lmf
1853                  */
1854                 /* This could be called before emit_push_lmf () */
1855                 if (!cfg->lmf_addr_var)
1856                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1857                 lmf_addr_reg = cfg->lmf_addr_var->dreg;
1858
1859                 prev_lmf_reg = alloc_preg (cfg);
1860                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
1861                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, prev_lmf_reg);
1862         }
1863 }
1864
1865 static void
1866 emit_instrumentation_call (MonoCompile *cfg, void *func)
1867 {
1868         MonoInst *iargs [1];
1869
1870         /*
1871          * Avoid instrumenting inlined methods since it can
1872          * distort profiling results.
1873          */
1874         if (cfg->method != cfg->current_method)
1875                 return;
1876
1877         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
1878                 EMIT_NEW_METHODCONST (cfg, iargs [0], cfg->method);
1879                 mono_emit_jit_icall (cfg, func, iargs);
1880         }
1881 }
1882
1883 static int
1884 ret_type_to_call_opcode (MonoCompile *cfg, MonoType *type, int calli, int virt)
1885 {
1886 handle_enum:
1887         type = mini_get_underlying_type (type);
1888         switch (type->type) {
1889         case MONO_TYPE_VOID:
1890                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALL_MEMBASE: OP_VOIDCALL;
1891         case MONO_TYPE_I1:
1892         case MONO_TYPE_U1:
1893         case MONO_TYPE_I2:
1894         case MONO_TYPE_U2:
1895         case MONO_TYPE_I4:
1896         case MONO_TYPE_U4:
1897                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
1898         case MONO_TYPE_I:
1899         case MONO_TYPE_U:
1900         case MONO_TYPE_PTR:
1901         case MONO_TYPE_FNPTR:
1902                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
1903         case MONO_TYPE_CLASS:
1904         case MONO_TYPE_STRING:
1905         case MONO_TYPE_OBJECT:
1906         case MONO_TYPE_SZARRAY:
1907         case MONO_TYPE_ARRAY:    
1908                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
1909         case MONO_TYPE_I8:
1910         case MONO_TYPE_U8:
1911                 return calli? OP_LCALL_REG: virt? OP_LCALL_MEMBASE: OP_LCALL;
1912         case MONO_TYPE_R4:
1913                 if (cfg->r4fp)
1914                         return calli? OP_RCALL_REG: virt? OP_RCALL_MEMBASE: OP_RCALL;
1915                 else
1916                         return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
1917         case MONO_TYPE_R8:
1918                 return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
1919         case MONO_TYPE_VALUETYPE:
1920                 if (type->data.klass->enumtype) {
1921                         type = mono_class_enum_basetype (type->data.klass);
1922                         goto handle_enum;
1923                 } else
1924                         return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
1925         case MONO_TYPE_TYPEDBYREF:
1926                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
1927         case MONO_TYPE_GENERICINST:
1928                 type = &type->data.generic_class->container_class->byval_arg;
1929                 goto handle_enum;
1930         case MONO_TYPE_VAR:
1931         case MONO_TYPE_MVAR:
1932                 /* gsharedvt */
1933                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
1934         default:
1935                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
1936         }
1937         return -1;
1938 }
1939
1940 //XXX this ignores if t is byref
1941 #define MONO_TYPE_IS_PRIMITIVE_SCALAR(t) ((((((t)->type >= MONO_TYPE_BOOLEAN && (t)->type <= MONO_TYPE_U8) || ((t)->type >= MONO_TYPE_I && (t)->type <= MONO_TYPE_U)))))
1942
1943 /*
1944  * target_type_is_incompatible:
1945  * @cfg: MonoCompile context
1946  *
1947  * Check that the item @arg on the evaluation stack can be stored
1948  * in the target type (can be a local, or field, etc).
1949  * The cfg arg can be used to check if we need verification or just
1950  * validity checks.
1951  *
1952  * Returns: non-0 value if arg can't be stored on a target.
1953  */
1954 static int
1955 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
1956 {
1957         MonoType *simple_type;
1958         MonoClass *klass;
1959
1960         if (target->byref) {
1961                 /* FIXME: check that the pointed to types match */
1962                 if (arg->type == STACK_MP) {
1963                         /* This is needed to handle gshared types + ldaddr. We lower the types so we can handle enums and other typedef-like types. */
1964                         MonoClass *target_class_lowered = mono_class_from_mono_type (mini_get_underlying_type (&mono_class_from_mono_type (target)->byval_arg));
1965                         MonoClass *source_class_lowered = mono_class_from_mono_type (mini_get_underlying_type (&arg->klass->byval_arg));
1966
1967                         /* if the target is native int& or same type */
1968                         if (target->type == MONO_TYPE_I || target_class_lowered == source_class_lowered)
1969                                 return 0;
1970
1971                         /* Both are primitive type byrefs and the source points to a larger type that the destination */
1972                         if (MONO_TYPE_IS_PRIMITIVE_SCALAR (&target_class_lowered->byval_arg) && MONO_TYPE_IS_PRIMITIVE_SCALAR (&source_class_lowered->byval_arg) &&
1973                                 mono_class_instance_size (target_class_lowered) <= mono_class_instance_size (source_class_lowered))
1974                                 return 0;
1975                         return 1;
1976                 }
1977                 if (arg->type == STACK_PTR)
1978                         return 0;
1979                 return 1;
1980         }
1981
1982         simple_type = mini_get_underlying_type (target);
1983         switch (simple_type->type) {
1984         case MONO_TYPE_VOID:
1985                 return 1;
1986         case MONO_TYPE_I1:
1987         case MONO_TYPE_U1:
1988         case MONO_TYPE_I2:
1989         case MONO_TYPE_U2:
1990         case MONO_TYPE_I4:
1991         case MONO_TYPE_U4:
1992                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
1993                         return 1;
1994                 return 0;
1995         case MONO_TYPE_PTR:
1996                 /* STACK_MP is needed when setting pinned locals */
1997                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
1998                         return 1;
1999                 return 0;
2000         case MONO_TYPE_I:
2001         case MONO_TYPE_U:
2002         case MONO_TYPE_FNPTR:
2003                 /* 
2004                  * Some opcodes like ldloca returns 'transient pointers' which can be stored in
2005                  * in native int. (#688008).
2006                  */
2007                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2008                         return 1;
2009                 return 0;
2010         case MONO_TYPE_CLASS:
2011         case MONO_TYPE_STRING:
2012         case MONO_TYPE_OBJECT:
2013         case MONO_TYPE_SZARRAY:
2014         case MONO_TYPE_ARRAY:    
2015                 if (arg->type != STACK_OBJ)
2016                         return 1;
2017                 /* FIXME: check type compatibility */
2018                 return 0;
2019         case MONO_TYPE_I8:
2020         case MONO_TYPE_U8:
2021                 if (arg->type != STACK_I8)
2022                         return 1;
2023                 return 0;
2024         case MONO_TYPE_R4:
2025                 if (arg->type != cfg->r4_stack_type)
2026                         return 1;
2027                 return 0;
2028         case MONO_TYPE_R8:
2029                 if (arg->type != STACK_R8)
2030                         return 1;
2031                 return 0;
2032         case MONO_TYPE_VALUETYPE:
2033                 if (arg->type != STACK_VTYPE)
2034                         return 1;
2035                 klass = mono_class_from_mono_type (simple_type);
2036                 if (klass != arg->klass)
2037                         return 1;
2038                 return 0;
2039         case MONO_TYPE_TYPEDBYREF:
2040                 if (arg->type != STACK_VTYPE)
2041                         return 1;
2042                 klass = mono_class_from_mono_type (simple_type);
2043                 if (klass != arg->klass)
2044                         return 1;
2045                 return 0;
2046         case MONO_TYPE_GENERICINST:
2047                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2048                         MonoClass *target_class;
2049                         if (arg->type != STACK_VTYPE)
2050                                 return 1;
2051                         klass = mono_class_from_mono_type (simple_type);
2052                         target_class = mono_class_from_mono_type (target);
2053                         /* The second cases is needed when doing partial sharing */
2054                         if (klass != arg->klass && target_class != arg->klass && target_class != mono_class_from_mono_type (mini_get_underlying_type (&arg->klass->byval_arg)))
2055                                 return 1;
2056                         return 0;
2057                 } else {
2058                         if (arg->type != STACK_OBJ)
2059                                 return 1;
2060                         /* FIXME: check type compatibility */
2061                         return 0;
2062                 }
2063         case MONO_TYPE_VAR:
2064         case MONO_TYPE_MVAR:
2065                 g_assert (cfg->gshared);
2066                 if (mini_type_var_is_vt (simple_type)) {
2067                         if (arg->type != STACK_VTYPE)
2068                                 return 1;
2069                 } else {
2070                         if (arg->type != STACK_OBJ)
2071                                 return 1;
2072                 }
2073                 return 0;
2074         default:
2075                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2076         }
2077         return 1;
2078 }
2079
2080 /*
2081  * Prepare arguments for passing to a function call.
2082  * Return a non-zero value if the arguments can't be passed to the given
2083  * signature.
2084  * The type checks are not yet complete and some conversions may need
2085  * casts on 32 or 64 bit architectures.
2086  *
2087  * FIXME: implement this using target_type_is_incompatible ()
2088  */
2089 static int
2090 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2091 {
2092         MonoType *simple_type;
2093         int i;
2094
2095         if (sig->hasthis) {
2096                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2097                         return 1;
2098                 args++;
2099         }
2100         for (i = 0; i < sig->param_count; ++i) {
2101                 if (sig->params [i]->byref) {
2102                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2103                                 return 1;
2104                         continue;
2105                 }
2106                 simple_type = mini_get_underlying_type (sig->params [i]);
2107 handle_enum:
2108                 switch (simple_type->type) {
2109                 case MONO_TYPE_VOID:
2110                         return 1;
2111                         continue;
2112                 case MONO_TYPE_I1:
2113                 case MONO_TYPE_U1:
2114                 case MONO_TYPE_I2:
2115                 case MONO_TYPE_U2:
2116                 case MONO_TYPE_I4:
2117                 case MONO_TYPE_U4:
2118                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2119                                 return 1;
2120                         continue;
2121                 case MONO_TYPE_I:
2122                 case MONO_TYPE_U:
2123                 case MONO_TYPE_PTR:
2124                 case MONO_TYPE_FNPTR:
2125                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2126                                 return 1;
2127                         continue;
2128                 case MONO_TYPE_CLASS:
2129                 case MONO_TYPE_STRING:
2130                 case MONO_TYPE_OBJECT:
2131                 case MONO_TYPE_SZARRAY:
2132                 case MONO_TYPE_ARRAY:    
2133                         if (args [i]->type != STACK_OBJ)
2134                                 return 1;
2135                         continue;
2136                 case MONO_TYPE_I8:
2137                 case MONO_TYPE_U8:
2138                         if (args [i]->type != STACK_I8)
2139                                 return 1;
2140                         continue;
2141                 case MONO_TYPE_R4:
2142                         if (args [i]->type != cfg->r4_stack_type)
2143                                 return 1;
2144                         continue;
2145                 case MONO_TYPE_R8:
2146                         if (args [i]->type != STACK_R8)
2147                                 return 1;
2148                         continue;
2149                 case MONO_TYPE_VALUETYPE:
2150                         if (simple_type->data.klass->enumtype) {
2151                                 simple_type = mono_class_enum_basetype (simple_type->data.klass);
2152                                 goto handle_enum;
2153                         }
2154                         if (args [i]->type != STACK_VTYPE)
2155                                 return 1;
2156                         continue;
2157                 case MONO_TYPE_TYPEDBYREF:
2158                         if (args [i]->type != STACK_VTYPE)
2159                                 return 1;
2160                         continue;
2161                 case MONO_TYPE_GENERICINST:
2162                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2163                         goto handle_enum;
2164                 case MONO_TYPE_VAR:
2165                 case MONO_TYPE_MVAR:
2166                         /* gsharedvt */
2167                         if (args [i]->type != STACK_VTYPE)
2168                                 return 1;
2169                         continue;
2170                 default:
2171                         g_error ("unknown type 0x%02x in check_call_signature",
2172                                  simple_type->type);
2173                 }
2174         }
2175         return 0;
2176 }
2177
2178 static int
2179 callvirt_to_call (int opcode)
2180 {
2181         switch (opcode) {
2182         case OP_CALL_MEMBASE:
2183                 return OP_CALL;
2184         case OP_VOIDCALL_MEMBASE:
2185                 return OP_VOIDCALL;
2186         case OP_FCALL_MEMBASE:
2187                 return OP_FCALL;
2188         case OP_RCALL_MEMBASE:
2189                 return OP_RCALL;
2190         case OP_VCALL_MEMBASE:
2191                 return OP_VCALL;
2192         case OP_LCALL_MEMBASE:
2193                 return OP_LCALL;
2194         default:
2195                 g_assert_not_reached ();
2196         }
2197
2198         return -1;
2199 }
2200
2201 static int
2202 callvirt_to_call_reg (int opcode)
2203 {
2204         switch (opcode) {
2205         case OP_CALL_MEMBASE:
2206                 return OP_CALL_REG;
2207         case OP_VOIDCALL_MEMBASE:
2208                 return OP_VOIDCALL_REG;
2209         case OP_FCALL_MEMBASE:
2210                 return OP_FCALL_REG;
2211         case OP_RCALL_MEMBASE:
2212                 return OP_RCALL_REG;
2213         case OP_VCALL_MEMBASE:
2214                 return OP_VCALL_REG;
2215         case OP_LCALL_MEMBASE:
2216                 return OP_LCALL_REG;
2217         default:
2218                 g_assert_not_reached ();
2219         }
2220
2221         return -1;
2222 }
2223
2224 /* Either METHOD or IMT_ARG needs to be set */
2225 static void
2226 emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoMethod *method, MonoInst *imt_arg)
2227 {
2228         int method_reg;
2229
2230         if (COMPILE_LLVM (cfg)) {
2231                 if (imt_arg) {
2232                         method_reg = alloc_preg (cfg);
2233                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2234                 } else {
2235                         MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
2236                         method_reg = ins->dreg;
2237                 }
2238
2239 #ifdef ENABLE_LLVM
2240                 call->imt_arg_reg = method_reg;
2241 #endif
2242                 mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2243                 return;
2244         }
2245
2246         if (imt_arg) {
2247                 method_reg = alloc_preg (cfg);
2248                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2249         } else {
2250                 MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
2251                 method_reg = ins->dreg;
2252         }
2253
2254         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2255 }
2256
2257 static MonoJumpInfo *
2258 mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpointer target)
2259 {
2260         MonoJumpInfo *ji = (MonoJumpInfo *)mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
2261
2262         ji->ip.i = ip;
2263         ji->type = type;
2264         ji->data.target = target;
2265
2266         return ji;
2267 }
2268
2269 static int
2270 mini_class_check_context_used (MonoCompile *cfg, MonoClass *klass)
2271 {
2272         if (cfg->gshared)
2273                 return mono_class_check_context_used (klass);
2274         else
2275                 return 0;
2276 }
2277
2278 static int
2279 mini_method_check_context_used (MonoCompile *cfg, MonoMethod *method)
2280 {
2281         if (cfg->gshared)
2282                 return mono_method_check_context_used (method);
2283         else
2284                 return 0;
2285 }
2286
2287 /*
2288  * check_method_sharing:
2289  *
2290  *   Check whenever the vtable or an mrgctx needs to be passed when calling CMETHOD.
2291  */
2292 static void
2293 check_method_sharing (MonoCompile *cfg, MonoMethod *cmethod, gboolean *out_pass_vtable, gboolean *out_pass_mrgctx)
2294 {
2295         gboolean pass_vtable = FALSE;
2296         gboolean pass_mrgctx = FALSE;
2297
2298         if (((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
2299                 (mono_class_is_ginst (cmethod->klass) || mono_class_is_gtd (cmethod->klass))) {
2300                 gboolean sharable = FALSE;
2301
2302                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE))
2303                         sharable = TRUE;
2304
2305                 /*
2306                  * Pass vtable iff target method might
2307                  * be shared, which means that sharing
2308                  * is enabled for its class and its
2309                  * context is sharable (and it's not a
2310                  * generic method).
2311                  */
2312                 if (sharable && !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
2313                         pass_vtable = TRUE;
2314         }
2315
2316         if (mini_method_get_context (cmethod) &&
2317                 mini_method_get_context (cmethod)->method_inst) {
2318                 g_assert (!pass_vtable);
2319
2320                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE)) {
2321                         pass_mrgctx = TRUE;
2322                 } else {
2323                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (mono_method_signature (cmethod)))
2324                                 pass_mrgctx = TRUE;
2325                 }
2326         }
2327
2328         if (out_pass_vtable)
2329                 *out_pass_vtable = pass_vtable;
2330         if (out_pass_mrgctx)
2331                 *out_pass_mrgctx = pass_mrgctx;
2332 }
2333
2334 inline static MonoCallInst *
2335 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
2336                                          MonoInst **args, int calli, int virtual_, int tail, int rgctx, int unbox_trampoline)
2337 {
2338         MonoType *sig_ret;
2339         MonoCallInst *call;
2340 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2341         int i;
2342 #endif
2343
2344         if (cfg->llvm_only)
2345                 tail = FALSE;
2346
2347         if (tail) {
2348                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
2349
2350                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
2351         } else
2352                 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (cfg, sig->ret, calli, virtual_));
2353
2354         call->args = args;
2355         call->signature = sig;
2356         call->rgctx_reg = rgctx;
2357         sig_ret = mini_get_underlying_type (sig->ret);
2358
2359         type_to_eval_stack_type ((cfg), sig_ret, &call->inst);
2360
2361         if (tail) {
2362                 if (mini_type_is_vtype (sig_ret)) {
2363                         call->vret_var = cfg->vret_addr;
2364                         //g_assert_not_reached ();
2365                 }
2366         } else if (mini_type_is_vtype (sig_ret)) {
2367                 MonoInst *temp = mono_compile_create_var (cfg, sig_ret, OP_LOCAL);
2368                 MonoInst *loada;
2369
2370                 temp->backend.is_pinvoke = sig->pinvoke;
2371
2372                 /*
2373                  * We use a new opcode OP_OUTARG_VTRETADDR instead of LDADDR for emitting the
2374                  * address of return value to increase optimization opportunities.
2375                  * Before vtype decomposition, the dreg of the call ins itself represents the
2376                  * fact the call modifies the return value. After decomposition, the call will
2377                  * be transformed into one of the OP_VOIDCALL opcodes, and the VTRETADDR opcode
2378                  * will be transformed into an LDADDR.
2379                  */
2380                 MONO_INST_NEW (cfg, loada, OP_OUTARG_VTRETADDR);
2381                 loada->dreg = alloc_preg (cfg);
2382                 loada->inst_p0 = temp;
2383                 /* We reference the call too since call->dreg could change during optimization */
2384                 loada->inst_p1 = call;
2385                 MONO_ADD_INS (cfg->cbb, loada);
2386
2387                 call->inst.dreg = temp->dreg;
2388
2389                 call->vret_var = loada;
2390         } else if (!MONO_TYPE_IS_VOID (sig_ret))
2391                 call->inst.dreg = alloc_dreg (cfg, (MonoStackType)call->inst.type);
2392
2393 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2394         if (COMPILE_SOFT_FLOAT (cfg)) {
2395                 /* 
2396                  * If the call has a float argument, we would need to do an r8->r4 conversion using 
2397                  * an icall, but that cannot be done during the call sequence since it would clobber
2398                  * the call registers + the stack. So we do it before emitting the call.
2399                  */
2400                 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2401                         MonoType *t;
2402                         MonoInst *in = call->args [i];
2403
2404                         if (i >= sig->hasthis)
2405                                 t = sig->params [i - sig->hasthis];
2406                         else
2407                                 t = &mono_defaults.int_class->byval_arg;
2408                         t = mono_type_get_underlying_type (t);
2409
2410                         if (!t->byref && t->type == MONO_TYPE_R4) {
2411                                 MonoInst *iargs [1];
2412                                 MonoInst *conv;
2413
2414                                 iargs [0] = in;
2415                                 conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
2416
2417                                 /* The result will be in an int vreg */
2418                                 call->args [i] = conv;
2419                         }
2420                 }
2421         }
2422 #endif
2423
2424         call->need_unbox_trampoline = unbox_trampoline;
2425
2426 #ifdef ENABLE_LLVM
2427         if (COMPILE_LLVM (cfg))
2428                 mono_llvm_emit_call (cfg, call);
2429         else
2430                 mono_arch_emit_call (cfg, call);
2431 #else
2432         mono_arch_emit_call (cfg, call);
2433 #endif
2434
2435         cfg->param_area = MAX (cfg->param_area, call->stack_usage);
2436         cfg->flags |= MONO_CFG_HAS_CALLS;
2437         
2438         return call;
2439 }
2440
2441 static void
2442 set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rgctx_arg)
2443 {
2444         mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
2445         cfg->uses_rgctx_reg = TRUE;
2446         call->rgctx_reg = TRUE;
2447 #ifdef ENABLE_LLVM
2448         call->rgctx_arg_reg = rgctx_reg;
2449 #endif
2450 }       
2451
2452 inline static MonoInst*
2453 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg)
2454 {
2455         MonoCallInst *call;
2456         MonoInst *ins;
2457         int rgctx_reg = -1;
2458         gboolean check_sp = FALSE;
2459
2460         if (cfg->check_pinvoke_callconv && cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
2461                 WrapperInfo *info = mono_marshal_get_wrapper_info (cfg->method);
2462
2463                 if (info && info->subtype == WRAPPER_SUBTYPE_PINVOKE)
2464                         check_sp = TRUE;
2465         }
2466
2467         if (rgctx_arg) {
2468                 rgctx_reg = mono_alloc_preg (cfg);
2469                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2470         }
2471
2472         if (check_sp) {
2473                 if (!cfg->stack_inbalance_var)
2474                         cfg->stack_inbalance_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2475
2476                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2477                 ins->dreg = cfg->stack_inbalance_var->dreg;
2478                 MONO_ADD_INS (cfg->cbb, ins);
2479         }
2480
2481         call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE);
2482
2483         call->inst.sreg1 = addr->dreg;
2484
2485         if (imt_arg)
2486                 emit_imt_argument (cfg, call, NULL, imt_arg);
2487
2488         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2489
2490         if (check_sp) {
2491                 int sp_reg;
2492
2493                 sp_reg = mono_alloc_preg (cfg);
2494
2495                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2496                 ins->dreg = sp_reg;
2497                 MONO_ADD_INS (cfg->cbb, ins);
2498
2499                 /* Restore the stack so we don't crash when throwing the exception */
2500                 MONO_INST_NEW (cfg, ins, OP_SET_SP);
2501                 ins->sreg1 = cfg->stack_inbalance_var->dreg;
2502                 MONO_ADD_INS (cfg->cbb, ins);
2503
2504                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, cfg->stack_inbalance_var->dreg, sp_reg);
2505                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ExecutionEngineException");
2506         }
2507
2508         if (rgctx_arg)
2509                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2510
2511         return (MonoInst*)call;
2512 }
2513
2514 static MonoInst*
2515 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2516
2517 static MonoInst*
2518 emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type);
2519
2520 static MonoInst*
2521 mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig, gboolean tail,
2522                                                         MonoInst **args, MonoInst *this_ins, MonoInst *imt_arg, MonoInst *rgctx_arg)
2523 {
2524 #ifndef DISABLE_REMOTING
2525         gboolean might_be_remote = FALSE;
2526 #endif
2527         gboolean virtual_ = this_ins != NULL;
2528         gboolean enable_for_aot = TRUE;
2529         int context_used;
2530         MonoCallInst *call;
2531         MonoInst *call_target = NULL;
2532         int rgctx_reg = 0;
2533         gboolean need_unbox_trampoline;
2534
2535         if (!sig)
2536                 sig = mono_method_signature (method);
2537
2538         if (cfg->llvm_only && (mono_class_is_interface (method->klass)))
2539                 g_assert_not_reached ();
2540
2541         if (rgctx_arg) {
2542                 rgctx_reg = mono_alloc_preg (cfg);
2543                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2544         }
2545
2546         if (method->string_ctor) {
2547                 /* Create the real signature */
2548                 /* FIXME: Cache these */
2549                 MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_mempool (cfg->mempool, sig);
2550                 ctor_sig->ret = &mono_defaults.string_class->byval_arg;
2551
2552                 sig = ctor_sig;
2553         }
2554
2555         context_used = mini_method_check_context_used (cfg, method);
2556
2557 #ifndef DISABLE_REMOTING
2558         might_be_remote = this_ins && sig->hasthis &&
2559                 (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) &&
2560                 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && (!MONO_CHECK_THIS (this_ins) || context_used);
2561
2562         if (might_be_remote && context_used) {
2563                 MonoInst *addr;
2564
2565                 g_assert (cfg->gshared);
2566
2567                 addr = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK);
2568
2569                 return mono_emit_calli (cfg, sig, args, addr, NULL, NULL);
2570         }
2571 #endif
2572
2573         if (cfg->llvm_only && !call_target && virtual_ && (method->flags & METHOD_ATTRIBUTE_VIRTUAL))
2574                 return emit_llvmonly_virtual_call (cfg, method, sig, 0, args);
2575
2576         need_unbox_trampoline = method->klass == mono_defaults.object_class || mono_class_is_interface (method->klass);
2577
2578         call = mono_emit_call_args (cfg, sig, args, FALSE, virtual_, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline);
2579
2580 #ifndef DISABLE_REMOTING
2581         if (might_be_remote)
2582                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2583         else
2584 #endif
2585                 call->method = method;
2586         call->inst.flags |= MONO_INST_HAS_METHOD;
2587         call->inst.inst_left = this_ins;
2588         call->tail_call = tail;
2589
2590         if (virtual_) {
2591                 int vtable_reg, slot_reg, this_reg;
2592                 int offset;
2593
2594                 this_reg = this_ins->dreg;
2595
2596                 if (!cfg->llvm_only && (method->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (method->name, "Invoke")) {
2597                         MonoInst *dummy_use;
2598
2599                         MONO_EMIT_NULL_CHECK (cfg, this_reg);
2600
2601                         /* Make a call to delegate->invoke_impl */
2602                         call->inst.inst_basereg = this_reg;
2603                         call->inst.inst_offset = MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl);
2604                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2605
2606                         /* We must emit a dummy use here because the delegate trampoline will
2607                         replace the 'this' argument with the delegate target making this activation
2608                         no longer a root for the delegate.
2609                         This is an issue for delegates that target collectible code such as dynamic
2610                         methods of GC'able assemblies.
2611
2612                         For a test case look into #667921.
2613
2614                         FIXME: a dummy use is not the best way to do it as the local register allocator
2615                         will put it on a caller save register and spil it around the call. 
2616                         Ideally, we would either put it on a callee save register or only do the store part.  
2617                          */
2618                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [0]);
2619
2620                         return (MonoInst*)call;
2621                 }
2622
2623                 if ((!cfg->compile_aot || enable_for_aot) && 
2624                         (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
2625                          (MONO_METHOD_IS_FINAL (method) &&
2626                           method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)) &&
2627                         !(mono_class_is_marshalbyref (method->klass) && context_used)) {
2628                         /* 
2629                          * the method is not virtual, we just need to ensure this is not null
2630                          * and then we can call the method directly.
2631                          */
2632 #ifndef DISABLE_REMOTING
2633                         if (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) {
2634                                 /* 
2635                                  * The check above ensures method is not gshared, this is needed since
2636                                  * gshared methods can't have wrappers.
2637                                  */
2638                                 method = call->method = mono_marshal_get_remoting_invoke_with_check (method);
2639                         }
2640 #endif
2641
2642                         if (!method->string_ctor)
2643                                 MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2644
2645                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2646                 } else if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && MONO_METHOD_IS_FINAL (method)) {
2647                         /*
2648                          * the method is virtual, but we can statically dispatch since either
2649                          * it's class or the method itself are sealed.
2650                          * But first we need to ensure it's not a null reference.
2651                          */
2652                         MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2653
2654                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2655                 } else if (call_target) {
2656                         vtable_reg = alloc_preg (cfg);
2657                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2658
2659                         call->inst.opcode = callvirt_to_call_reg (call->inst.opcode);
2660                         call->inst.sreg1 = call_target->dreg;
2661                         call->inst.flags &= !MONO_INST_HAS_METHOD;
2662                 } else {
2663                         vtable_reg = alloc_preg (cfg);
2664                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2665                         if (mono_class_is_interface (method->klass)) {
2666                                 guint32 imt_slot = mono_method_get_imt_slot (method);
2667                                 emit_imt_argument (cfg, call, call->method, imt_arg);
2668                                 slot_reg = vtable_reg;
2669                                 offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
2670                         } else {
2671                                 slot_reg = vtable_reg;
2672                                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) +
2673                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
2674                                 if (imt_arg) {
2675                                         g_assert (mono_method_signature (method)->generic_param_count);
2676                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2677                                 }
2678                         }
2679
2680                         call->inst.sreg1 = slot_reg;
2681                         call->inst.inst_offset = offset;
2682                         call->is_virtual = TRUE;
2683                 }
2684         }
2685
2686         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2687
2688         if (rgctx_arg)
2689                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2690
2691         return (MonoInst*)call;
2692 }
2693
2694 MonoInst*
2695 mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this_ins)
2696 {
2697         return mono_emit_method_call_full (cfg, method, mono_method_signature (method), FALSE, args, this_ins, NULL, NULL);
2698 }
2699
2700 MonoInst*
2701 mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig,
2702                                            MonoInst **args)
2703 {
2704         MonoCallInst *call;
2705
2706         g_assert (sig);
2707
2708         call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE, FALSE, FALSE);
2709         call->fptr = func;
2710
2711         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2712
2713         return (MonoInst*)call;
2714 }
2715
2716 MonoInst*
2717 mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args)
2718 {
2719         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2720
2721         g_assert (info);
2722
2723         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2724 }
2725
2726 /*
2727  * mono_emit_abs_call:
2728  *
2729  *   Emit a call to the runtime function described by PATCH_TYPE and DATA.
2730  */
2731 inline static MonoInst*
2732 mono_emit_abs_call (MonoCompile *cfg, MonoJumpInfoType patch_type, gconstpointer data, 
2733                                         MonoMethodSignature *sig, MonoInst **args)
2734 {
2735         MonoJumpInfo *ji = mono_patch_info_new (cfg->mempool, 0, patch_type, data);
2736         MonoInst *ins;
2737
2738         /* 
2739          * We pass ji as the call address, the PATCH_INFO_ABS resolving code will
2740          * handle it.
2741          */
2742         if (cfg->abs_patches == NULL)
2743                 cfg->abs_patches = g_hash_table_new (NULL, NULL);
2744         g_hash_table_insert (cfg->abs_patches, ji, ji);
2745         ins = mono_emit_native_call (cfg, ji, sig, args);
2746         ((MonoCallInst*)ins)->fptr_is_patch = TRUE;
2747         return ins;
2748 }
2749
2750 static MonoMethodSignature*
2751 sig_to_rgctx_sig (MonoMethodSignature *sig)
2752 {
2753         // FIXME: memory allocation
2754         MonoMethodSignature *res;
2755         int i;
2756
2757         res = (MonoMethodSignature *)g_malloc (MONO_SIZEOF_METHOD_SIGNATURE + (sig->param_count + 1) * sizeof (MonoType*));
2758         memcpy (res, sig, MONO_SIZEOF_METHOD_SIGNATURE);
2759         res->param_count = sig->param_count + 1;
2760         for (i = 0; i < sig->param_count; ++i)
2761                 res->params [i] = sig->params [i];
2762         res->params [sig->param_count] = &mono_defaults.int_class->this_arg;
2763         return res;
2764 }
2765
2766 /* Make an indirect call to FSIG passing an additional argument */
2767 static MonoInst*
2768 emit_extra_arg_calli (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **orig_args, int arg_reg, MonoInst *call_target)
2769 {
2770         MonoMethodSignature *csig;
2771         MonoInst *args_buf [16];
2772         MonoInst **args;
2773         int i, pindex, tmp_reg;
2774
2775         /* Make a call with an rgctx/extra arg */
2776         if (fsig->param_count + 2 < 16)
2777                 args = args_buf;
2778         else
2779                 args = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (fsig->param_count + 2));
2780         pindex = 0;
2781         if (fsig->hasthis)
2782                 args [pindex ++] = orig_args [0];
2783         for (i = 0; i < fsig->param_count; ++i)
2784                 args [pindex ++] = orig_args [fsig->hasthis + i];
2785         tmp_reg = alloc_preg (cfg);
2786         EMIT_NEW_UNALU (cfg, args [pindex], OP_MOVE, tmp_reg, arg_reg);
2787         csig = sig_to_rgctx_sig (fsig);
2788         return mono_emit_calli (cfg, csig, args, call_target, NULL, NULL);
2789 }
2790
2791 /* Emit an indirect call to the function descriptor ADDR */
2792 static MonoInst*
2793 emit_llvmonly_calli (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, MonoInst *addr)
2794 {
2795         int addr_reg, arg_reg;
2796         MonoInst *call_target;
2797
2798         g_assert (cfg->llvm_only);
2799
2800         /*
2801          * addr points to a <addr, arg> pair, load both of them, and
2802          * make a call to addr, passing arg as an extra arg.
2803          */
2804         addr_reg = alloc_preg (cfg);
2805         EMIT_NEW_LOAD_MEMBASE (cfg, call_target, OP_LOAD_MEMBASE, addr_reg, addr->dreg, 0);
2806         arg_reg = alloc_preg (cfg);
2807         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, arg_reg, addr->dreg, sizeof (gpointer));
2808
2809         return emit_extra_arg_calli (cfg, fsig, args, arg_reg, call_target);
2810 }
2811
2812 static gboolean
2813 direct_icalls_enabled (MonoCompile *cfg)
2814 {
2815         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
2816 #ifdef TARGET_AMD64
2817         if (cfg->compile_llvm && !cfg->llvm_only)
2818                 return FALSE;
2819 #endif
2820         if (cfg->gen_sdb_seq_points || cfg->disable_direct_icalls)
2821                 return FALSE;
2822         return TRUE;
2823 }
2824
2825 MonoInst*
2826 mono_emit_jit_icall_by_info (MonoCompile *cfg, int il_offset, MonoJitICallInfo *info, MonoInst **args)
2827 {
2828         /*
2829          * Call the jit icall without a wrapper if possible.
2830          * The wrapper is needed for the following reasons:
2831          * - to handle exceptions thrown using mono_raise_exceptions () from the
2832          *   icall function. The EH code needs the lmf frame pushed by the
2833          *   wrapper to be able to unwind back to managed code.
2834          * - to be able to do stack walks for asynchronously suspended
2835          *   threads when debugging.
2836          */
2837         if (info->no_raise && direct_icalls_enabled (cfg)) {
2838                 char *name;
2839                 int costs;
2840
2841                 if (!info->wrapper_method) {
2842                         name = g_strdup_printf ("__icall_wrapper_%s", info->name);
2843                         info->wrapper_method = mono_marshal_get_icall_wrapper (info->sig, name, info->func, TRUE);
2844                         g_free (name);
2845                         mono_memory_barrier ();
2846                 }
2847
2848                 /*
2849                  * Inline the wrapper method, which is basically a call to the C icall, and
2850                  * an exception check.
2851                  */
2852                 costs = inline_method (cfg, info->wrapper_method, NULL,
2853                                                            args, NULL, il_offset, TRUE);
2854                 g_assert (costs > 0);
2855                 g_assert (!MONO_TYPE_IS_VOID (info->sig->ret));
2856
2857                 return args [0];
2858         } else {
2859                 return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2860         }
2861 }
2862  
2863 static MonoInst*
2864 mono_emit_widen_call_res (MonoCompile *cfg, MonoInst *ins, MonoMethodSignature *fsig)
2865 {
2866         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
2867                 if ((fsig->pinvoke || LLVM_ENABLED) && !fsig->ret->byref) {
2868                         int widen_op = -1;
2869
2870                         /* 
2871                          * Native code might return non register sized integers 
2872                          * without initializing the upper bits.
2873                          */
2874                         switch (mono_type_to_load_membase (cfg, fsig->ret)) {
2875                         case OP_LOADI1_MEMBASE:
2876                                 widen_op = OP_ICONV_TO_I1;
2877                                 break;
2878                         case OP_LOADU1_MEMBASE:
2879                                 widen_op = OP_ICONV_TO_U1;
2880                                 break;
2881                         case OP_LOADI2_MEMBASE:
2882                                 widen_op = OP_ICONV_TO_I2;
2883                                 break;
2884                         case OP_LOADU2_MEMBASE:
2885                                 widen_op = OP_ICONV_TO_U2;
2886                                 break;
2887                         default:
2888                                 break;
2889                         }
2890
2891                         if (widen_op != -1) {
2892                                 int dreg = alloc_preg (cfg);
2893                                 MonoInst *widen;
2894
2895                                 EMIT_NEW_UNALU (cfg, widen, widen_op, dreg, ins->dreg);
2896                                 widen->type = ins->type;
2897                                 ins = widen;
2898                         }
2899                 }
2900         }
2901
2902         return ins;
2903 }
2904
2905
2906 static void
2907 emit_method_access_failure (MonoCompile *cfg, MonoMethod *method, MonoMethod *cil_method)
2908 {
2909         MonoInst *args [16];
2910
2911         args [0] = emit_get_rgctx_method (cfg, mono_method_check_context_used (method), method, MONO_RGCTX_INFO_METHOD);
2912         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cil_method), cil_method, MONO_RGCTX_INFO_METHOD);
2913
2914         mono_emit_jit_icall (cfg, mono_throw_method_access, args);
2915 }
2916
2917 static MonoMethod*
2918 get_memcpy_method (void)
2919 {
2920         static MonoMethod *memcpy_method = NULL;
2921         if (!memcpy_method) {
2922                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
2923                 if (!memcpy_method)
2924                         g_error ("Old corlib found. Install a new one");
2925         }
2926         return memcpy_method;
2927 }
2928
2929 static void
2930 create_write_barrier_bitmap (MonoCompile *cfg, MonoClass *klass, unsigned *wb_bitmap, int offset)
2931 {
2932         MonoClassField *field;
2933         gpointer iter = NULL;
2934
2935         while ((field = mono_class_get_fields (klass, &iter))) {
2936                 int foffset;
2937
2938                 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
2939                         continue;
2940                 foffset = klass->valuetype ? field->offset - sizeof (MonoObject): field->offset;
2941                 if (mini_type_is_reference (mono_field_get_type (field))) {
2942                         g_assert ((foffset % SIZEOF_VOID_P) == 0);
2943                         *wb_bitmap |= 1 << ((offset + foffset) / SIZEOF_VOID_P);
2944                 } else {
2945                         MonoClass *field_class = mono_class_from_mono_type (field->type);
2946                         if (field_class->has_references)
2947                                 create_write_barrier_bitmap (cfg, field_class, wb_bitmap, offset + foffset);
2948                 }
2949         }
2950 }
2951
2952 static void
2953 emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value)
2954 {
2955         int card_table_shift_bits;
2956         gpointer card_table_mask;
2957         guint8 *card_table;
2958         MonoInst *dummy_use;
2959         int nursery_shift_bits;
2960         size_t nursery_size;
2961
2962         if (!cfg->gen_write_barriers)
2963                 return;
2964
2965         card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
2966
2967         mono_gc_get_nursery (&nursery_shift_bits, &nursery_size);
2968
2969         if (cfg->backend->have_card_table_wb && !cfg->compile_aot && card_table && nursery_shift_bits > 0 && !COMPILE_LLVM (cfg)) {
2970                 MonoInst *wbarrier;
2971
2972                 MONO_INST_NEW (cfg, wbarrier, OP_CARD_TABLE_WBARRIER);
2973                 wbarrier->sreg1 = ptr->dreg;
2974                 wbarrier->sreg2 = value->dreg;
2975                 MONO_ADD_INS (cfg->cbb, wbarrier);
2976         } else if (card_table && !cfg->compile_aot && !mono_gc_card_table_nursery_check ()) {
2977                 int offset_reg = alloc_preg (cfg);
2978                 int card_reg;
2979                 MonoInst *ins;
2980
2981                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, offset_reg, ptr->dreg, card_table_shift_bits);
2982                 if (card_table_mask)
2983                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, offset_reg, offset_reg, card_table_mask);
2984
2985                 /*We can't use PADD_IMM since the cardtable might end up in high addresses and amd64 doesn't support
2986                  * IMM's larger than 32bits.
2987                  */
2988                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
2989                 card_reg = ins->dreg;
2990
2991                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, offset_reg, offset_reg, card_reg);
2992                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, offset_reg, 0, 1);
2993         } else {
2994                 MonoMethod *write_barrier = mono_gc_get_write_barrier ();
2995                 mono_emit_method_call (cfg, write_barrier, &ptr, NULL);
2996         }
2997
2998         EMIT_NEW_DUMMY_USE (cfg, dummy_use, value);
2999 }
3000
3001 static gboolean
3002 mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align)
3003 {
3004         int dest_ptr_reg, tmp_reg, destreg, srcreg, offset;
3005         unsigned need_wb = 0;
3006
3007         if (align == 0)
3008                 align = 4;
3009
3010         /*types with references can't have alignment smaller than sizeof(void*) */
3011         if (align < SIZEOF_VOID_P)
3012                 return FALSE;
3013
3014         /*This value cannot be bigger than 32 due to the way we calculate the required wb bitmap.*/
3015         if (size > 32 * SIZEOF_VOID_P)
3016                 return FALSE;
3017
3018         create_write_barrier_bitmap (cfg, klass, &need_wb, 0);
3019
3020         /* We don't unroll more than 5 stores to avoid code bloat. */
3021         if (size > 5 * SIZEOF_VOID_P) {
3022                 /*This is harmless and simplify mono_gc_wbarrier_value_copy_bitmap */
3023                 size += (SIZEOF_VOID_P - 1);
3024                 size &= ~(SIZEOF_VOID_P - 1);
3025
3026                 EMIT_NEW_ICONST (cfg, iargs [2], size);
3027                 EMIT_NEW_ICONST (cfg, iargs [3], need_wb);
3028                 mono_emit_jit_icall (cfg, mono_gc_wbarrier_value_copy_bitmap, iargs);
3029                 return TRUE;
3030         }
3031
3032         destreg = iargs [0]->dreg;
3033         srcreg = iargs [1]->dreg;
3034         offset = 0;
3035
3036         dest_ptr_reg = alloc_preg (cfg);
3037         tmp_reg = alloc_preg (cfg);
3038
3039         /*tmp = dreg*/
3040         EMIT_NEW_UNALU (cfg, iargs [0], OP_MOVE, dest_ptr_reg, destreg);
3041
3042         while (size >= SIZEOF_VOID_P) {
3043                 MonoInst *load_inst;
3044                 MONO_INST_NEW (cfg, load_inst, OP_LOAD_MEMBASE);
3045                 load_inst->dreg = tmp_reg;
3046                 load_inst->inst_basereg = srcreg;
3047                 load_inst->inst_offset = offset;
3048                 MONO_ADD_INS (cfg->cbb, load_inst);
3049
3050                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg);
3051
3052                 if (need_wb & 0x1)
3053                         emit_write_barrier (cfg, iargs [0], load_inst);
3054
3055                 offset += SIZEOF_VOID_P;
3056                 size -= SIZEOF_VOID_P;
3057                 need_wb >>= 1;
3058
3059                 /*tmp += sizeof (void*)*/
3060                 if (size >= SIZEOF_VOID_P) {
3061                         NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dest_ptr_reg, dest_ptr_reg, SIZEOF_VOID_P);
3062                         MONO_ADD_INS (cfg->cbb, iargs [0]);
3063                 }
3064         }
3065
3066         /* Those cannot be references since size < sizeof (void*) */
3067         while (size >= 4) {
3068                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tmp_reg, srcreg, offset);
3069                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, tmp_reg);
3070                 offset += 4;
3071                 size -= 4;
3072         }
3073
3074         while (size >= 2) {
3075                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmp_reg, srcreg, offset);
3076                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, tmp_reg);
3077                 offset += 2;
3078                 size -= 2;
3079         }
3080
3081         while (size >= 1) {
3082                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmp_reg, srcreg, offset);
3083                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, tmp_reg);
3084                 offset += 1;
3085                 size -= 1;
3086         }
3087
3088         return TRUE;
3089 }
3090
3091 /*
3092  * Emit code to copy a valuetype of type @klass whose address is stored in
3093  * @src->dreg to memory whose address is stored at @dest->dreg.
3094  */
3095 void
3096 mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native)
3097 {
3098         MonoInst *iargs [4];
3099         int n;
3100         guint32 align = 0;
3101         MonoMethod *memcpy_method;
3102         MonoInst *size_ins = NULL;
3103         MonoInst *memcpy_ins = NULL;
3104
3105         g_assert (klass);
3106         if (cfg->gshared)
3107                 klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
3108
3109         /*
3110          * This check breaks with spilled vars... need to handle it during verification anyway.
3111          * g_assert (klass && klass == src->klass && klass == dest->klass);
3112          */
3113
3114         if (mini_is_gsharedvt_klass (klass)) {
3115                 g_assert (!native);
3116                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3117                 memcpy_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_MEMCPY);
3118         }
3119
3120         if (native)
3121                 n = mono_class_native_size (klass, &align);
3122         else
3123                 n = mono_class_value_size (klass, &align);
3124
3125         /* if native is true there should be no references in the struct */
3126         if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) {
3127                 /* Avoid barriers when storing to the stack */
3128                 if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
3129                           (dest->opcode == OP_LDADDR))) {
3130                         int context_used;
3131
3132                         iargs [0] = dest;
3133                         iargs [1] = src;
3134
3135                         context_used = mini_class_check_context_used (cfg, klass);
3136
3137                         /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
3138                         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
3139                                 return;
3140                         } else if (context_used) {
3141                                 iargs [2] = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3142                         }  else {
3143                                 iargs [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
3144                                 if (!cfg->compile_aot)
3145                                         mono_class_compute_gc_descriptor (klass);
3146                         }
3147
3148                         if (size_ins)
3149                                 mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
3150                         else
3151                                 mono_emit_jit_icall (cfg, mono_value_copy, iargs);
3152                         return;
3153                 }
3154         }
3155
3156         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 8) {
3157                 /* FIXME: Optimize the case when src/dest is OP_LDADDR */
3158                 mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, n, align);
3159         } else {
3160                 iargs [0] = dest;
3161                 iargs [1] = src;
3162                 if (size_ins)
3163                         iargs [2] = size_ins;
3164                 else
3165                         EMIT_NEW_ICONST (cfg, iargs [2], n);
3166                 
3167                 memcpy_method = get_memcpy_method ();
3168                 if (memcpy_ins)
3169                         mono_emit_calli (cfg, mono_method_signature (memcpy_method), iargs, memcpy_ins, NULL, NULL);
3170                 else
3171                         mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
3172         }
3173 }
3174
3175 static MonoMethod*
3176 get_memset_method (void)
3177 {
3178         static MonoMethod *memset_method = NULL;
3179         if (!memset_method) {
3180                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
3181                 if (!memset_method)
3182                         g_error ("Old corlib found. Install a new one");
3183         }
3184         return memset_method;
3185 }
3186
3187 void
3188 mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass)
3189 {
3190         MonoInst *iargs [3];
3191         int n;
3192         guint32 align;
3193         MonoMethod *memset_method;
3194         MonoInst *size_ins = NULL;
3195         MonoInst *bzero_ins = NULL;
3196         static MonoMethod *bzero_method;
3197
3198         /* FIXME: Optimize this for the case when dest is an LDADDR */
3199         mono_class_init (klass);
3200         if (mini_is_gsharedvt_klass (klass)) {
3201                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3202                 bzero_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_BZERO);
3203                 if (!bzero_method)
3204                         bzero_method = mono_class_get_method_from_name (mono_defaults.string_class, "bzero_aligned_1", 2);
3205                 g_assert (bzero_method);
3206                 iargs [0] = dest;
3207                 iargs [1] = size_ins;
3208                 mono_emit_calli (cfg, mono_method_signature (bzero_method), iargs, bzero_ins, NULL, NULL);
3209                 return;
3210         }
3211
3212         klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
3213
3214         n = mono_class_value_size (klass, &align);
3215
3216         if (n <= sizeof (gpointer) * 8) {
3217                 mini_emit_memset (cfg, dest->dreg, 0, n, 0, align);
3218         }
3219         else {
3220                 memset_method = get_memset_method ();
3221                 iargs [0] = dest;
3222                 EMIT_NEW_ICONST (cfg, iargs [1], 0);
3223                 EMIT_NEW_ICONST (cfg, iargs [2], n);
3224                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
3225         }
3226 }
3227
3228 /*
3229  * emit_get_rgctx:
3230  *
3231  *   Emit IR to return either the this pointer for instance method,
3232  * or the mrgctx for static methods.
3233  */
3234 static MonoInst*
3235 emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used)
3236 {
3237         MonoInst *this_ins = NULL;
3238
3239         g_assert (cfg->gshared);
3240
3241         if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&
3242                         !(context_used & MONO_GENERIC_CONTEXT_USED_METHOD) &&
3243                         !method->klass->valuetype)
3244                 EMIT_NEW_ARGLOAD (cfg, this_ins, 0);
3245
3246         if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
3247                 MonoInst *mrgctx_loc, *mrgctx_var;
3248
3249                 g_assert (!this_ins);
3250                 g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
3251
3252                 mrgctx_loc = mono_get_vtable_var (cfg);
3253                 EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
3254
3255                 return mrgctx_var;
3256         } else if (method->flags & METHOD_ATTRIBUTE_STATIC || method->klass->valuetype) {
3257                 MonoInst *vtable_loc, *vtable_var;
3258
3259                 g_assert (!this_ins);
3260
3261                 vtable_loc = mono_get_vtable_var (cfg);
3262                 EMIT_NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
3263
3264                 if (method->is_inflated && mono_method_get_context (method)->method_inst) {
3265                         MonoInst *mrgctx_var = vtable_var;
3266                         int vtable_reg;
3267
3268                         vtable_reg = alloc_preg (cfg);
3269                         EMIT_NEW_LOAD_MEMBASE (cfg, vtable_var, OP_LOAD_MEMBASE, vtable_reg, mrgctx_var->dreg, MONO_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable));
3270                         vtable_var->type = STACK_PTR;
3271                 }
3272
3273                 return vtable_var;
3274         } else {
3275                 MonoInst *ins;
3276                 int vtable_reg;
3277         
3278                 vtable_reg = alloc_preg (cfg);
3279                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, vtable_reg, this_ins->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3280                 return ins;
3281         }
3282 }
3283
3284 static MonoJumpInfoRgctxEntry *
3285 mono_patch_info_rgctx_entry_new (MonoMemPool *mp, MonoMethod *method, gboolean in_mrgctx, MonoJumpInfoType patch_type, gconstpointer patch_data, MonoRgctxInfoType info_type)
3286 {
3287         MonoJumpInfoRgctxEntry *res = (MonoJumpInfoRgctxEntry *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoRgctxEntry));
3288         res->method = method;
3289         res->in_mrgctx = in_mrgctx;
3290         res->data = (MonoJumpInfo *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
3291         res->data->type = patch_type;
3292         res->data->data.target = patch_data;
3293         res->info_type = info_type;
3294
3295         return res;
3296 }
3297
3298 static inline MonoInst*
3299 emit_rgctx_fetch_inline (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3300 {
3301         MonoInst *args [16];
3302         MonoInst *call;
3303
3304         // FIXME: No fastpath since the slot is not a compile time constant
3305         args [0] = rgctx;
3306         EMIT_NEW_AOTCONST (cfg, args [1], MONO_PATCH_INFO_RGCTX_SLOT_INDEX, entry);
3307         if (entry->in_mrgctx)
3308                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3309         else
3310                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3311         return call;
3312 #if 0
3313         /*
3314          * FIXME: This can be called during decompose, which is a problem since it creates
3315          * new bblocks.
3316          * Also, the fastpath doesn't work since the slot number is dynamically allocated.
3317          */
3318         int i, slot, depth, index, rgctx_reg, val_reg, res_reg;
3319         gboolean mrgctx;
3320         MonoBasicBlock *is_null_bb, *end_bb;
3321         MonoInst *res, *ins, *call;
3322         MonoInst *args[16];
3323
3324         slot = mini_get_rgctx_entry_slot (entry);
3325
3326         mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot);
3327         index = MONO_RGCTX_SLOT_INDEX (slot);
3328         if (mrgctx)
3329                 index += MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
3330         for (depth = 0; ; ++depth) {
3331                 int size = mono_class_rgctx_get_array_size (depth, mrgctx);
3332
3333                 if (index < size - 1)
3334                         break;
3335                 index -= size - 1;
3336         }
3337
3338         NEW_BBLOCK (cfg, end_bb);
3339         NEW_BBLOCK (cfg, is_null_bb);
3340
3341         if (mrgctx) {
3342                 rgctx_reg = rgctx->dreg;
3343         } else {
3344                 rgctx_reg = alloc_preg (cfg);
3345
3346                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, rgctx_reg, rgctx->dreg, MONO_STRUCT_OFFSET (MonoVTable, runtime_generic_context));
3347                 // FIXME: Avoid this check by allocating the table when the vtable is created etc.
3348                 NEW_BBLOCK (cfg, is_null_bb);
3349
3350                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3351                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3352         }
3353
3354         for (i = 0; i < depth; ++i) {
3355                 int array_reg = alloc_preg (cfg);
3356
3357                 /* load ptr to next array */
3358                 if (mrgctx && i == 0)
3359                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT);
3360                 else
3361                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, 0);
3362                 rgctx_reg = array_reg;
3363                 /* is the ptr null? */
3364                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3365                 /* if yes, jump to actual trampoline */
3366                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3367         }
3368
3369         /* fetch slot */
3370         val_reg = alloc_preg (cfg);
3371         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, val_reg, rgctx_reg, (index + 1) * sizeof (gpointer));
3372         /* is the slot null? */
3373         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, val_reg, 0);
3374         /* if yes, jump to actual trampoline */
3375         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3376
3377         /* Fastpath */
3378         res_reg = alloc_preg (cfg);
3379         MONO_INST_NEW (cfg, ins, OP_MOVE);
3380         ins->dreg = res_reg;
3381         ins->sreg1 = val_reg;
3382         MONO_ADD_INS (cfg->cbb, ins);
3383         res = ins;
3384         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3385
3386         /* Slowpath */
3387         MONO_START_BB (cfg, is_null_bb);
3388         args [0] = rgctx;
3389         EMIT_NEW_ICONST (cfg, args [1], index);
3390         if (mrgctx)
3391                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3392         else
3393                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3394         MONO_INST_NEW (cfg, ins, OP_MOVE);
3395         ins->dreg = res_reg;
3396         ins->sreg1 = call->dreg;
3397         MONO_ADD_INS (cfg->cbb, ins);
3398         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3399
3400         MONO_START_BB (cfg, end_bb);
3401
3402         return res;
3403 #endif
3404 }
3405
3406 /*
3407  * emit_rgctx_fetch:
3408  *
3409  *   Emit IR to load the value of the rgctx entry ENTRY from the rgctx
3410  * given by RGCTX.
3411  */
3412 static inline MonoInst*
3413 emit_rgctx_fetch (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3414 {
3415         if (cfg->llvm_only)
3416                 return emit_rgctx_fetch_inline (cfg, rgctx, entry);
3417         else
3418                 return mono_emit_abs_call (cfg, MONO_PATCH_INFO_RGCTX_FETCH, entry, helper_sig_rgctx_lazy_fetch_trampoline, &rgctx);
3419 }
3420
3421 MonoInst*
3422 mini_emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
3423                                           MonoClass *klass, MonoRgctxInfoType rgctx_type)
3424 {
3425         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);
3426         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3427
3428         return emit_rgctx_fetch (cfg, rgctx, entry);
3429 }
3430
3431 static MonoInst*
3432 emit_get_rgctx_sig (MonoCompile *cfg, int context_used,
3433                                         MonoMethodSignature *sig, MonoRgctxInfoType rgctx_type)
3434 {
3435         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);
3436         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3437
3438         return emit_rgctx_fetch (cfg, rgctx, entry);
3439 }
3440
3441 static MonoInst*
3442 emit_get_rgctx_gsharedvt_call (MonoCompile *cfg, int context_used,
3443                                                            MonoMethodSignature *sig, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3444 {
3445         MonoJumpInfoGSharedVtCall *call_info;
3446         MonoJumpInfoRgctxEntry *entry;
3447         MonoInst *rgctx;
3448
3449         call_info = (MonoJumpInfoGSharedVtCall *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoGSharedVtCall));
3450         call_info->sig = sig;
3451         call_info->method = cmethod;
3452
3453         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);
3454         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3455
3456         return emit_rgctx_fetch (cfg, rgctx, entry);
3457 }
3458
3459 /*
3460  * emit_get_rgctx_virt_method:
3461  *
3462  *   Return data for method VIRT_METHOD for a receiver of type KLASS.
3463  */
3464 static MonoInst*
3465 emit_get_rgctx_virt_method (MonoCompile *cfg, int context_used,
3466                                                         MonoClass *klass, MonoMethod *virt_method, MonoRgctxInfoType rgctx_type)
3467 {
3468         MonoJumpInfoVirtMethod *info;
3469         MonoJumpInfoRgctxEntry *entry;
3470         MonoInst *rgctx;
3471
3472         info = (MonoJumpInfoVirtMethod *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoVirtMethod));
3473         info->klass = klass;
3474         info->method = virt_method;
3475
3476         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);
3477         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3478
3479         return emit_rgctx_fetch (cfg, rgctx, entry);
3480 }
3481
3482 static MonoInst*
3483 emit_get_rgctx_gsharedvt_method (MonoCompile *cfg, int context_used,
3484                                                                  MonoMethod *cmethod, MonoGSharedVtMethodInfo *info)
3485 {
3486         MonoJumpInfoRgctxEntry *entry;
3487         MonoInst *rgctx;
3488
3489         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);
3490         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3491
3492         return emit_rgctx_fetch (cfg, rgctx, entry);
3493 }
3494
3495 /*
3496  * emit_get_rgctx_method:
3497  *
3498  *   Emit IR to load the property RGCTX_TYPE of CMETHOD. If context_used is 0, emit
3499  * normal constants, else emit a load from the rgctx.
3500  */
3501 static MonoInst*
3502 emit_get_rgctx_method (MonoCompile *cfg, int context_used,
3503                                            MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3504 {
3505         if (!context_used) {
3506                 MonoInst *ins;
3507
3508                 switch (rgctx_type) {
3509                 case MONO_RGCTX_INFO_METHOD:
3510                         EMIT_NEW_METHODCONST (cfg, ins, cmethod);
3511                         return ins;
3512                 case MONO_RGCTX_INFO_METHOD_RGCTX:
3513                         EMIT_NEW_METHOD_RGCTX_CONST (cfg, ins, cmethod);
3514                         return ins;
3515                 default:
3516                         g_assert_not_reached ();
3517                 }
3518         } else {
3519                 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);
3520                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3521
3522                 return emit_rgctx_fetch (cfg, rgctx, entry);
3523         }
3524 }
3525
3526 static MonoInst*
3527 emit_get_rgctx_field (MonoCompile *cfg, int context_used,
3528                                           MonoClassField *field, MonoRgctxInfoType rgctx_type)
3529 {
3530         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);
3531         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3532
3533         return emit_rgctx_fetch (cfg, rgctx, entry);
3534 }
3535
3536 static int
3537 get_gsharedvt_info_slot (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3538 {
3539         MonoGSharedVtMethodInfo *info = cfg->gsharedvt_info;
3540         MonoRuntimeGenericContextInfoTemplate *template_;
3541         int i, idx;
3542
3543         g_assert (info);
3544
3545         for (i = 0; i < info->num_entries; ++i) {
3546                 MonoRuntimeGenericContextInfoTemplate *otemplate = &info->entries [i];
3547
3548                 if (otemplate->info_type == rgctx_type && otemplate->data == data && rgctx_type != MONO_RGCTX_INFO_LOCAL_OFFSET)
3549                         return i;
3550         }
3551
3552         if (info->num_entries == info->count_entries) {
3553                 MonoRuntimeGenericContextInfoTemplate *new_entries;
3554                 int new_count_entries = info->count_entries ? info->count_entries * 2 : 16;
3555
3556                 new_entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * new_count_entries);
3557
3558                 memcpy (new_entries, info->entries, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
3559                 info->entries = new_entries;
3560                 info->count_entries = new_count_entries;
3561         }
3562
3563         idx = info->num_entries;
3564         template_ = &info->entries [idx];
3565         template_->info_type = rgctx_type;
3566         template_->data = data;
3567
3568         info->num_entries ++;
3569
3570         return idx;
3571 }
3572
3573 /*
3574  * emit_get_gsharedvt_info:
3575  *
3576  *   This is similar to emit_get_rgctx_.., but loads the data from the gsharedvt info var instead of calling an rgctx fetch trampoline.
3577  */
3578 static MonoInst*
3579 emit_get_gsharedvt_info (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3580 {
3581         MonoInst *ins;
3582         int idx, dreg;
3583
3584         idx = get_gsharedvt_info_slot (cfg, data, rgctx_type);
3585         /* Load info->entries [idx] */
3586         dreg = alloc_preg (cfg);
3587         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, cfg->gsharedvt_info_var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
3588
3589         return ins;
3590 }
3591
3592 static MonoInst*
3593 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type)
3594 {
3595         return emit_get_gsharedvt_info (cfg, &klass->byval_arg, rgctx_type);
3596 }
3597
3598 /*
3599  * On return the caller must check @klass for load errors.
3600  */
3601 static void
3602 emit_class_init (MonoCompile *cfg, MonoClass *klass)
3603 {
3604         MonoInst *vtable_arg;
3605         int context_used;
3606
3607         context_used = mini_class_check_context_used (cfg, klass);
3608
3609         if (context_used) {
3610                 vtable_arg = mini_emit_get_rgctx_klass (cfg, context_used,
3611                                                                                    klass, MONO_RGCTX_INFO_VTABLE);
3612         } else {
3613                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3614
3615                 if (!vtable)
3616                         return;
3617                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
3618         }
3619
3620         if (!COMPILE_LLVM (cfg) && cfg->backend->have_op_generic_class_init) {
3621                 MonoInst *ins;
3622
3623                 /*
3624                  * Using an opcode instead of emitting IR here allows the hiding of the call inside the opcode,
3625                  * so this doesn't have to clobber any regs and it doesn't break basic blocks.
3626                  */
3627                 MONO_INST_NEW (cfg, ins, OP_GENERIC_CLASS_INIT);
3628                 ins->sreg1 = vtable_arg->dreg;
3629                 MONO_ADD_INS (cfg->cbb, ins);
3630         } else {
3631                 static int byte_offset = -1;
3632                 static guint8 bitmask;
3633                 int bits_reg, inited_reg;
3634                 MonoBasicBlock *inited_bb;
3635                 MonoInst *args [16];
3636
3637                 if (byte_offset < 0)
3638                         mono_marshal_find_bitfield_offset (MonoVTable, initialized, &byte_offset, &bitmask);
3639
3640                 bits_reg = alloc_ireg (cfg);
3641                 inited_reg = alloc_ireg (cfg);
3642
3643                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, bits_reg, vtable_arg->dreg, byte_offset);
3644                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, inited_reg, bits_reg, bitmask);
3645
3646                 NEW_BBLOCK (cfg, inited_bb);
3647
3648                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, inited_reg, 0);
3649                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, inited_bb);
3650
3651                 args [0] = vtable_arg;
3652                 mono_emit_jit_icall (cfg, mono_generic_class_init, args);
3653
3654                 MONO_START_BB (cfg, inited_bb);
3655         }
3656 }
3657
3658 static void
3659 emit_seq_point (MonoCompile *cfg, MonoMethod *method, guint8* ip, gboolean intr_loc, gboolean nonempty_stack)
3660 {
3661         MonoInst *ins;
3662
3663         if (cfg->gen_seq_points && cfg->method == method) {
3664                 NEW_SEQ_POINT (cfg, ins, ip - cfg->header->code, intr_loc);
3665                 if (nonempty_stack)
3666                         ins->flags |= MONO_INST_NONEMPTY_STACK;
3667                 MONO_ADD_INS (cfg->cbb, ins);
3668         }
3669 }
3670
3671 void
3672 mini_save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean null_check)
3673 {
3674         if (mini_get_debug_options ()->better_cast_details) {
3675                 int vtable_reg = alloc_preg (cfg);
3676                 int klass_reg = alloc_preg (cfg);
3677                 MonoBasicBlock *is_null_bb = NULL;
3678                 MonoInst *tls_get;
3679                 int to_klass_reg, context_used;
3680
3681                 if (null_check) {
3682                         NEW_BBLOCK (cfg, is_null_bb);
3683
3684                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3685                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3686                 }
3687
3688                 tls_get = mono_get_jit_tls_intrinsic (cfg);
3689                 if (!tls_get) {
3690                         fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
3691                         exit (1);
3692                 }
3693
3694                 MONO_ADD_INS (cfg->cbb, tls_get);
3695                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3696                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3697
3698                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
3699
3700                 context_used = mini_class_check_context_used (cfg, klass);
3701                 if (context_used) {
3702                         MonoInst *class_ins;
3703
3704                         class_ins = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3705                         to_klass_reg = class_ins->dreg;
3706                 } else {
3707                         to_klass_reg = alloc_preg (cfg);
3708                         MONO_EMIT_NEW_CLASSCONST (cfg, to_klass_reg, klass);
3709                 }
3710                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
3711
3712                 if (null_check)
3713                         MONO_START_BB (cfg, is_null_bb);
3714         }
3715 }
3716
3717 void
3718 mini_reset_cast_details (MonoCompile *cfg)
3719 {
3720         /* Reset the variables holding the cast details */
3721         if (mini_get_debug_options ()->better_cast_details) {
3722                 MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
3723
3724                 MONO_ADD_INS (cfg->cbb, tls_get);
3725                 /* It is enough to reset the from field */
3726                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
3727         }
3728 }
3729
3730 /*
3731  * On return the caller must check @array_class for load errors
3732  */
3733 static void
3734 mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_class)
3735 {
3736         int vtable_reg = alloc_preg (cfg);
3737         int context_used;
3738
3739         context_used = mini_class_check_context_used (cfg, array_class);
3740
3741         mini_save_cast_details (cfg, array_class, obj->dreg, FALSE);
3742
3743         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3744
3745         if (cfg->opt & MONO_OPT_SHARED) {
3746                 int class_reg = alloc_preg (cfg);
3747                 MonoInst *ins;
3748
3749                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, class_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3750                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, array_class);
3751                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, class_reg, ins->dreg);
3752         } else if (context_used) {
3753                 MonoInst *vtable_ins;
3754
3755                 vtable_ins = mini_emit_get_rgctx_klass (cfg, context_used, array_class, MONO_RGCTX_INFO_VTABLE);
3756                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vtable_ins->dreg);
3757         } else {
3758                 if (cfg->compile_aot) {
3759                         int vt_reg;
3760                         MonoVTable *vtable;
3761
3762                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3763                                 return;
3764                         vt_reg = alloc_preg (cfg);
3765                         MONO_EMIT_NEW_VTABLECONST (cfg, vt_reg, vtable);
3766                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vt_reg);
3767                 } else {
3768                         MonoVTable *vtable;
3769                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3770                                 return;
3771                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vtable);
3772                 }
3773         }
3774         
3775         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
3776
3777         mini_reset_cast_details (cfg);
3778 }
3779
3780 /**
3781  * Handles unbox of a Nullable<T>. If context_used is non zero, then shared 
3782  * generic code is generated.
3783  */
3784 static MonoInst*
3785 handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int context_used)
3786 {
3787         MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
3788
3789         if (context_used) {
3790                 MonoInst *rgctx, *addr;
3791
3792                 /* FIXME: What if the class is shared?  We might not
3793                    have to get the address of the method from the
3794                    RGCTX. */
3795                 addr = emit_get_rgctx_method (cfg, context_used, method,
3796                                                                           MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
3797                 if (cfg->llvm_only) {
3798                         cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, mono_method_signature (method));
3799                         return emit_llvmonly_calli (cfg, mono_method_signature (method), &val, addr);
3800                 } else {
3801                         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3802
3803                         return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
3804                 }
3805         } else {
3806                 gboolean pass_vtable, pass_mrgctx;
3807                 MonoInst *rgctx_arg = NULL;
3808
3809                 check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
3810                 g_assert (!pass_mrgctx);
3811
3812                 if (pass_vtable) {
3813                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
3814
3815                         g_assert (vtable);
3816                         EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
3817                 }
3818
3819                 return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
3820         }
3821 }
3822
3823 static MonoInst*
3824 handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_used)
3825 {
3826         MonoInst *add;
3827         int obj_reg;
3828         int vtable_reg = alloc_dreg (cfg ,STACK_PTR);
3829         int klass_reg = alloc_dreg (cfg ,STACK_PTR);
3830         int eclass_reg = alloc_dreg (cfg ,STACK_PTR);
3831         int rank_reg = alloc_dreg (cfg ,STACK_I4);
3832
3833         obj_reg = sp [0]->dreg;
3834         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3835         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
3836
3837         /* FIXME: generics */
3838         g_assert (klass->rank == 0);
3839                         
3840         // Check rank == 0
3841         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 0);
3842         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3843
3844         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3845         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, element_class));
3846
3847         if (context_used) {
3848                 MonoInst *element_class;
3849
3850                 /* This assertion is from the unboxcast insn */
3851                 g_assert (klass->rank == 0);
3852
3853                 element_class = mini_emit_get_rgctx_klass (cfg, context_used,
3854                                 klass, MONO_RGCTX_INFO_ELEMENT_KLASS);
3855
3856                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, eclass_reg, element_class->dreg);
3857                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3858         } else {
3859                 mini_save_cast_details (cfg, klass->element_class, obj_reg, FALSE);
3860                 mini_emit_class_check (cfg, eclass_reg, klass->element_class);
3861                 mini_reset_cast_details (cfg);
3862         }
3863
3864         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), obj_reg, sizeof (MonoObject));
3865         MONO_ADD_INS (cfg->cbb, add);
3866         add->type = STACK_MP;
3867         add->klass = klass;
3868
3869         return add;
3870 }
3871
3872 static MonoInst*
3873 handle_unbox_gsharedvt (MonoCompile *cfg, MonoClass *klass, MonoInst *obj)
3874 {
3875         MonoInst *addr, *klass_inst, *is_ref, *args[16];
3876         MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
3877         MonoInst *ins;
3878         int dreg, addr_reg;
3879
3880         klass_inst = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_KLASS);
3881
3882         /* obj */
3883         args [0] = obj;
3884
3885         /* klass */
3886         args [1] = klass_inst;
3887
3888         /* CASTCLASS */
3889         obj = mono_emit_jit_icall (cfg, mono_object_castclass_unbox, args);
3890
3891         NEW_BBLOCK (cfg, is_ref_bb);
3892         NEW_BBLOCK (cfg, is_nullable_bb);
3893         NEW_BBLOCK (cfg, end_bb);
3894         is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
3895         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
3896         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
3897
3898         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
3899         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
3900
3901         /* This will contain either the address of the unboxed vtype, or an address of the temporary where the ref is stored */
3902         addr_reg = alloc_dreg (cfg, STACK_MP);
3903
3904         /* Non-ref case */
3905         /* UNBOX */
3906         NEW_BIALU_IMM (cfg, addr, OP_ADD_IMM, addr_reg, obj->dreg, sizeof (MonoObject));
3907         MONO_ADD_INS (cfg->cbb, addr);
3908
3909         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3910
3911         /* Ref case */
3912         MONO_START_BB (cfg, is_ref_bb);
3913
3914         /* Save the ref to a temporary */
3915         dreg = alloc_ireg (cfg);
3916         EMIT_NEW_VARLOADA_VREG (cfg, addr, dreg, &klass->byval_arg);
3917         addr->dreg = addr_reg;
3918         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, obj->dreg);
3919         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3920
3921         /* Nullable case */
3922         MONO_START_BB (cfg, is_nullable_bb);
3923
3924         {
3925                 MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX);
3926                 MonoInst *unbox_call;
3927                 MonoMethodSignature *unbox_sig;
3928
3929                 unbox_sig = (MonoMethodSignature *)mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
3930                 unbox_sig->ret = &klass->byval_arg;
3931                 unbox_sig->param_count = 1;
3932                 unbox_sig->params [0] = &mono_defaults.object_class->byval_arg;
3933
3934                 if (cfg->llvm_only)
3935                         unbox_call = emit_llvmonly_calli (cfg, unbox_sig, &obj, addr);
3936                 else
3937                         unbox_call = mono_emit_calli (cfg, unbox_sig, &obj, addr, NULL, NULL);
3938
3939                 EMIT_NEW_VARLOADA_VREG (cfg, addr, unbox_call->dreg, &klass->byval_arg);
3940                 addr->dreg = addr_reg;
3941         }
3942
3943         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3944
3945         /* End */
3946         MONO_START_BB (cfg, end_bb);
3947
3948         /* LDOBJ */
3949         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr_reg, 0);
3950
3951         return ins;
3952 }
3953
3954 /*
3955  * Returns NULL and set the cfg exception on error.
3956  */
3957 static MonoInst*
3958 handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_used)
3959 {
3960         MonoInst *iargs [2];
3961         void *alloc_ftn;
3962
3963         if (context_used) {
3964                 MonoInst *data;
3965                 MonoRgctxInfoType rgctx_info;
3966                 MonoInst *iargs [2];
3967                 gboolean known_instance_size = !mini_is_gsharedvt_klass (klass);
3968
3969                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (klass, for_box, known_instance_size);
3970
3971                 if (cfg->opt & MONO_OPT_SHARED)
3972                         rgctx_info = MONO_RGCTX_INFO_KLASS;
3973                 else
3974                         rgctx_info = MONO_RGCTX_INFO_VTABLE;
3975                 data = mini_emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
3976
3977                 if (cfg->opt & MONO_OPT_SHARED) {
3978                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
3979                         iargs [1] = data;
3980                         alloc_ftn = ves_icall_object_new;
3981                 } else {
3982                         iargs [0] = data;
3983                         alloc_ftn = ves_icall_object_new_specific;
3984                 }
3985
3986                 if (managed_alloc && !(cfg->opt & MONO_OPT_SHARED)) {
3987                         if (known_instance_size) {
3988                                 int size = mono_class_instance_size (klass);
3989                                 if (size < sizeof (MonoObject))
3990                                         g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
3991
3992                                 EMIT_NEW_ICONST (cfg, iargs [1], size);
3993                         }
3994                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
3995                 }
3996
3997                 return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
3998         }
3999
4000         if (cfg->opt & MONO_OPT_SHARED) {
4001                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4002                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
4003
4004                 alloc_ftn = ves_icall_object_new;
4005         } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !mono_class_is_ginst (klass)) {
4006                 /* This happens often in argument checking code, eg. throw new FooException... */
4007                 /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
4008                 EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
4009                 return mono_emit_jit_icall (cfg, mono_helper_newobj_mscorlib, iargs);
4010         } else {
4011                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
4012                 MonoMethod *managed_alloc = NULL;
4013                 gboolean pass_lw;
4014
4015                 if (!vtable) {
4016                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4017                         cfg->exception_ptr = klass;
4018                         return NULL;
4019                 }
4020
4021                 managed_alloc = mono_gc_get_managed_allocator (klass, for_box, TRUE);
4022
4023                 if (managed_alloc) {
4024                         int size = mono_class_instance_size (klass);
4025                         if (size < sizeof (MonoObject))
4026                                 g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4027
4028                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4029                         EMIT_NEW_ICONST (cfg, iargs [1], size);
4030                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4031                 }
4032                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
4033                 if (pass_lw) {
4034                         guint32 lw = vtable->klass->instance_size;
4035                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
4036                         EMIT_NEW_ICONST (cfg, iargs [0], lw);
4037                         EMIT_NEW_VTABLECONST (cfg, iargs [1], vtable);
4038                 }
4039                 else {
4040                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4041                 }
4042         }
4043
4044         return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4045 }
4046         
4047 /*
4048  * Returns NULL and set the cfg exception on error.
4049  */     
4050 static MonoInst*
4051 handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used)
4052 {
4053         MonoInst *alloc, *ins;
4054
4055         if (mono_class_is_nullable (klass)) {
4056                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
4057
4058                 if (context_used) {
4059                         if (cfg->llvm_only && cfg->gsharedvt) {
4060                                 MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4061                                                                                                                 MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4062                                 return emit_llvmonly_calli (cfg, mono_method_signature (method), &val, addr);
4063                         } else {
4064                                 /* FIXME: What if the class is shared?  We might not
4065                                    have to get the method address from the RGCTX. */
4066                                 MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4067                                                                                                                 MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4068                                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
4069
4070                                 return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
4071                         }
4072                 } else {
4073                         gboolean pass_vtable, pass_mrgctx;
4074                         MonoInst *rgctx_arg = NULL;
4075
4076                         check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
4077                         g_assert (!pass_mrgctx);
4078
4079                         if (pass_vtable) {
4080                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4081
4082                                 g_assert (vtable);
4083                                 EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4084                         }
4085
4086                         return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4087                 }
4088         }
4089
4090         if (mini_is_gsharedvt_klass (klass)) {
4091                 MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4092                 MonoInst *res, *is_ref, *src_var, *addr;
4093                 int dreg;
4094
4095                 dreg = alloc_ireg (cfg);
4096
4097                 NEW_BBLOCK (cfg, is_ref_bb);
4098                 NEW_BBLOCK (cfg, is_nullable_bb);
4099                 NEW_BBLOCK (cfg, end_bb);
4100                 is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4101                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
4102                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4103
4104                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
4105                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4106
4107                 /* Non-ref case */
4108                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4109                 if (!alloc)
4110                         return NULL;
4111                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4112                 ins->opcode = OP_STOREV_MEMBASE;
4113
4114                 EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, alloc->dreg);
4115                 res->type = STACK_OBJ;
4116                 res->klass = klass;
4117                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4118                 
4119                 /* Ref case */
4120                 MONO_START_BB (cfg, is_ref_bb);
4121
4122                 /* val is a vtype, so has to load the value manually */
4123                 src_var = get_vreg_to_inst (cfg, val->dreg);
4124                 if (!src_var)
4125                         src_var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, val->dreg);
4126                 EMIT_NEW_VARLOADA (cfg, addr, src_var, src_var->inst_vtype);
4127                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, addr->dreg, 0);
4128                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4129
4130                 /* Nullable case */
4131                 MONO_START_BB (cfg, is_nullable_bb);
4132
4133                 {
4134                         MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass,
4135                                                                                                         MONO_RGCTX_INFO_NULLABLE_CLASS_BOX);
4136                         MonoInst *box_call;
4137                         MonoMethodSignature *box_sig;
4138
4139                         /*
4140                          * klass is Nullable<T>, need to call Nullable<T>.Box () using a gsharedvt signature, but we cannot
4141                          * construct that method at JIT time, so have to do things by hand.
4142                          */
4143                         box_sig = (MonoMethodSignature *)mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4144                         box_sig->ret = &mono_defaults.object_class->byval_arg;
4145                         box_sig->param_count = 1;
4146                         box_sig->params [0] = &klass->byval_arg;
4147
4148                         if (cfg->llvm_only)
4149                                 box_call = emit_llvmonly_calli (cfg, box_sig, &val, addr);
4150                         else
4151                                 box_call = mono_emit_calli (cfg, box_sig, &val, addr, NULL, NULL);
4152                         EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, box_call->dreg);
4153                         res->type = STACK_OBJ;
4154                         res->klass = klass;
4155                 }
4156
4157                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4158
4159                 MONO_START_BB (cfg, end_bb);
4160
4161                 return res;
4162         } else {
4163                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4164                 if (!alloc)
4165                         return NULL;
4166
4167                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4168                 return alloc;
4169         }
4170 }
4171
4172 static GHashTable* direct_icall_type_hash;
4173
4174 static gboolean
4175 icall_is_direct_callable (MonoCompile *cfg, MonoMethod *cmethod)
4176 {
4177         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
4178         if (!direct_icalls_enabled (cfg))
4179                 return FALSE;
4180
4181         /*
4182          * An icall is directly callable if it doesn't directly or indirectly call mono_raise_exception ().
4183          * Whitelist a few icalls for now.
4184          */
4185         if (!direct_icall_type_hash) {
4186                 GHashTable *h = g_hash_table_new (g_str_hash, g_str_equal);
4187
4188                 g_hash_table_insert (h, (char*)"Decimal", GUINT_TO_POINTER (1));
4189                 g_hash_table_insert (h, (char*)"Number", GUINT_TO_POINTER (1));
4190                 g_hash_table_insert (h, (char*)"Buffer", GUINT_TO_POINTER (1));
4191                 g_hash_table_insert (h, (char*)"Monitor", GUINT_TO_POINTER (1));
4192                 mono_memory_barrier ();
4193                 direct_icall_type_hash = h;
4194         }
4195
4196         if (cmethod->klass == mono_defaults.math_class)
4197                 return TRUE;
4198         /* No locking needed */
4199         if (cmethod->klass->image == mono_defaults.corlib && g_hash_table_lookup (direct_icall_type_hash, cmethod->klass->name))
4200                 return TRUE;
4201         return FALSE;
4202 }
4203
4204 static gboolean
4205 method_needs_stack_walk (MonoCompile *cfg, MonoMethod *cmethod)
4206 {
4207         if (cmethod->klass == mono_defaults.systemtype_class) {
4208                 if (!strcmp (cmethod->name, "GetType"))
4209                         return TRUE;
4210         }
4211         return FALSE;
4212 }
4213
4214 static G_GNUC_UNUSED MonoInst*
4215 handle_enum_has_flag (MonoCompile *cfg, MonoClass *klass, MonoInst *enum_this, MonoInst *enum_flag)
4216 {
4217         MonoType *enum_type = mono_type_get_underlying_type (&klass->byval_arg);
4218         guint32 load_opc = mono_type_to_load_membase (cfg, enum_type);
4219         gboolean is_i4;
4220
4221         switch (enum_type->type) {
4222         case MONO_TYPE_I8:
4223         case MONO_TYPE_U8:
4224 #if SIZEOF_REGISTER == 8
4225         case MONO_TYPE_I:
4226         case MONO_TYPE_U:
4227 #endif
4228                 is_i4 = FALSE;
4229                 break;
4230         default:
4231                 is_i4 = TRUE;
4232                 break;
4233         }
4234
4235         {
4236                 MonoInst *load, *and_, *cmp, *ceq;
4237                 int enum_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4238                 int and_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4239                 int dest_reg = alloc_ireg (cfg);
4240
4241                 EMIT_NEW_LOAD_MEMBASE (cfg, load, load_opc, enum_reg, enum_this->dreg, 0);
4242                 EMIT_NEW_BIALU (cfg, and_, is_i4 ? OP_IAND : OP_LAND, and_reg, enum_reg, enum_flag->dreg);
4243                 EMIT_NEW_BIALU (cfg, cmp, is_i4 ? OP_ICOMPARE : OP_LCOMPARE, -1, and_reg, enum_flag->dreg);
4244                 EMIT_NEW_UNALU (cfg, ceq, is_i4 ? OP_ICEQ : OP_LCEQ, dest_reg, -1);
4245
4246                 ceq->type = STACK_I4;
4247
4248                 if (!is_i4) {
4249                         load = mono_decompose_opcode (cfg, load);
4250                         and_ = mono_decompose_opcode (cfg, and_);
4251                         cmp = mono_decompose_opcode (cfg, cmp);
4252                         ceq = mono_decompose_opcode (cfg, ceq);
4253                 }
4254
4255                 return ceq;
4256         }
4257 }
4258
4259 /*
4260  * Returns NULL and set the cfg exception on error.
4261  */
4262 static G_GNUC_UNUSED MonoInst*
4263 handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used, gboolean virtual_)
4264 {
4265         MonoInst *ptr;
4266         int dreg;
4267         gpointer trampoline;
4268         MonoInst *obj, *method_ins, *tramp_ins;
4269         MonoDomain *domain;
4270         guint8 **code_slot;
4271
4272         if (virtual_ && !cfg->llvm_only) {
4273                 MonoMethod *invoke = mono_get_delegate_invoke (klass);
4274                 g_assert (invoke);
4275
4276                 if (!mono_get_delegate_virtual_invoke_impl (mono_method_signature (invoke), context_used ? NULL : method))
4277                         return NULL;
4278         }
4279
4280         obj = handle_alloc (cfg, klass, FALSE, mono_class_check_context_used (klass));
4281         if (!obj)
4282                 return NULL;
4283
4284         /* Inline the contents of mono_delegate_ctor */
4285
4286         /* Set target field */
4287         /* Optimize away setting of NULL target */
4288         if (!MONO_INS_IS_PCONST_NULL (target)) {
4289                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
4290                 if (cfg->gen_write_barriers) {
4291                         dreg = alloc_preg (cfg);
4292                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target));
4293                         emit_write_barrier (cfg, ptr, target);
4294                 }
4295         }
4296
4297         /* Set method field */
4298         method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
4299         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
4300
4301         /* 
4302          * To avoid looking up the compiled code belonging to the target method
4303          * in mono_delegate_trampoline (), we allocate a per-domain memory slot to
4304          * store it, and we fill it after the method has been compiled.
4305          */
4306         if (!method->dynamic && !(cfg->opt & MONO_OPT_SHARED)) {
4307                 MonoInst *code_slot_ins;
4308
4309                 if (context_used) {
4310                         code_slot_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD_DELEGATE_CODE);
4311                 } else {
4312                         domain = mono_domain_get ();
4313                         mono_domain_lock (domain);
4314                         if (!domain_jit_info (domain)->method_code_hash)
4315                                 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
4316                         code_slot = (guint8 **)g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
4317                         if (!code_slot) {
4318                                 code_slot = (guint8 **)mono_domain_alloc0 (domain, sizeof (gpointer));
4319                                 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
4320                         }
4321                         mono_domain_unlock (domain);
4322
4323                         code_slot_ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHOD_CODE_SLOT, method);
4324                 }
4325                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);                
4326         }
4327
4328         if (cfg->llvm_only) {
4329                 MonoInst *args [16];
4330
4331                 if (virtual_) {
4332                         args [0] = obj;
4333                         args [1] = target;
4334                         args [2] = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
4335                         mono_emit_jit_icall (cfg, mono_llvmonly_init_delegate_virtual, args);
4336                 } else {
4337                         args [0] = obj;
4338                         mono_emit_jit_icall (cfg, mono_llvmonly_init_delegate, args);
4339                 }
4340
4341                 return obj;
4342         }
4343
4344         if (cfg->compile_aot) {
4345                 MonoDelegateClassMethodPair *del_tramp;
4346
4347                 del_tramp = (MonoDelegateClassMethodPair *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoDelegateClassMethodPair));
4348                 del_tramp->klass = klass;
4349                 del_tramp->method = context_used ? NULL : method;
4350                 del_tramp->is_virtual = virtual_;
4351                 EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_DELEGATE_TRAMPOLINE, del_tramp);
4352         } else {
4353                 if (virtual_)
4354                         trampoline = mono_create_delegate_virtual_trampoline (cfg->domain, klass, context_used ? NULL : method);
4355                 else
4356                         trampoline = mono_create_delegate_trampoline_info (cfg->domain, klass, context_used ? NULL : method);
4357                 EMIT_NEW_PCONST (cfg, tramp_ins, trampoline);
4358         }
4359
4360         /* Set invoke_impl field */
4361         if (virtual_) {
4362                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), tramp_ins->dreg);
4363         } else {
4364                 dreg = alloc_preg (cfg);
4365                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, invoke_impl));
4366                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), dreg);
4367
4368                 dreg = alloc_preg (cfg);
4369                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, method_ptr));
4370                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), dreg);
4371         }
4372
4373         dreg = alloc_preg (cfg);
4374         MONO_EMIT_NEW_ICONST (cfg, dreg, virtual_ ? 1 : 0);
4375         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_is_virtual), dreg);
4376
4377         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
4378
4379         return obj;
4380 }
4381
4382 static MonoInst*
4383 handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
4384 {
4385         MonoJitICallInfo *info;
4386
4387         /* Need to register the icall so it gets an icall wrapper */
4388         info = mono_get_array_new_va_icall (rank);
4389
4390         cfg->flags |= MONO_CFG_HAS_VARARGS;
4391
4392         /* mono_array_new_va () needs a vararg calling convention */
4393         cfg->exception_message = g_strdup ("array-new");
4394         cfg->disable_llvm = TRUE;
4395
4396         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
4397         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
4398 }
4399
4400 /*
4401  * handle_constrained_gsharedvt_call:
4402  *
4403  *   Handle constrained calls where the receiver is a gsharedvt type.
4404  * Return the instruction representing the call. Set the cfg exception on failure.
4405  */
4406 static MonoInst*
4407 handle_constrained_gsharedvt_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp, MonoClass *constrained_class,
4408                                                                    gboolean *ref_emit_widen)
4409 {
4410         MonoInst *ins = NULL;
4411         gboolean emit_widen = *ref_emit_widen;
4412
4413         /*
4414          * Constrained calls need to behave differently at runtime dependending on whenever the receiver is instantiated as ref type or as a vtype.
4415          * 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
4416          * pack the arguments into an array, and do the rest of the work in in an icall.
4417          */
4418         if (((cmethod->klass == mono_defaults.object_class) || mono_class_is_interface (cmethod->klass) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) &&
4419                 (MONO_TYPE_IS_VOID (fsig->ret) || MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_IS_REFERENCE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret) || mini_is_gsharedvt_type (fsig->ret)) &&
4420                 (fsig->param_count == 0 || (!fsig->hasthis && fsig->param_count == 1) || (fsig->param_count == 1 && (MONO_TYPE_IS_REFERENCE (fsig->params [0]) || fsig->params [0]->byref || mini_is_gsharedvt_type (fsig->params [0]))))) {
4421                 MonoInst *args [16];
4422
4423                 /*
4424                  * This case handles calls to
4425                  * - object:ToString()/Equals()/GetHashCode(),
4426                  * - System.IComparable<T>:CompareTo()
4427                  * - System.IEquatable<T>:Equals ()
4428                  * plus some simple interface calls enough to support AsyncTaskMethodBuilder.
4429                  */
4430
4431                 args [0] = sp [0];
4432                 if (mono_method_check_context_used (cmethod))
4433                         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cmethod), cmethod, MONO_RGCTX_INFO_METHOD);
4434                 else
4435                         EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
4436                 args [2] = mini_emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_class), constrained_class, MONO_RGCTX_INFO_KLASS);
4437
4438                 /* !fsig->hasthis is for the wrapper for the Object.GetType () icall */
4439                 if (fsig->hasthis && fsig->param_count) {
4440                         /* Pass the arguments using a localloc-ed array using the format expected by runtime_invoke () */
4441                         MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
4442                         ins->dreg = alloc_preg (cfg);
4443                         ins->inst_imm = fsig->param_count * sizeof (mgreg_t);
4444                         MONO_ADD_INS (cfg->cbb, ins);
4445                         args [4] = ins;
4446
4447                         if (mini_is_gsharedvt_type (fsig->params [0])) {
4448                                 int addr_reg, deref_arg_reg;
4449
4450                                 ins = emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4451                                 deref_arg_reg = alloc_preg (cfg);
4452                                 /* deref_arg = BOX_TYPE != MONO_GSHAREDVT_BOX_TYPE_VTYPE */
4453                                 EMIT_NEW_BIALU_IMM (cfg, args [3], OP_ISUB_IMM, deref_arg_reg, ins->dreg, 1);
4454
4455                                 EMIT_NEW_VARLOADA_VREG (cfg, ins, sp [1]->dreg, fsig->params [0]);
4456                                 addr_reg = ins->dreg;
4457                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, addr_reg);
4458                         } else {
4459                                 EMIT_NEW_ICONST (cfg, args [3], 0);
4460                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, sp [1]->dreg);
4461                         }
4462                 } else {
4463                         EMIT_NEW_ICONST (cfg, args [3], 0);
4464                         EMIT_NEW_ICONST (cfg, args [4], 0);
4465                 }
4466                 ins = mono_emit_jit_icall (cfg, mono_gsharedvt_constrained_call, args);
4467                 emit_widen = FALSE;
4468
4469                 if (mini_is_gsharedvt_type (fsig->ret)) {
4470                         ins = handle_unbox_gsharedvt (cfg, mono_class_from_mono_type (fsig->ret), ins);
4471                 } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret)) {
4472                         MonoInst *add;
4473
4474                         /* Unbox */
4475                         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), ins->dreg, sizeof (MonoObject));
4476                         MONO_ADD_INS (cfg->cbb, add);
4477                         /* Load value */
4478                         NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, add->dreg, 0);
4479                         MONO_ADD_INS (cfg->cbb, ins);
4480                         /* ins represents the call result */
4481                 }
4482         } else {
4483                 GSHAREDVT_FAILURE (CEE_CALLVIRT);
4484         }
4485
4486         *ref_emit_widen = emit_widen;
4487
4488         return ins;
4489
4490  exception_exit:
4491         return NULL;
4492 }
4493
4494 static void
4495 mono_emit_load_got_addr (MonoCompile *cfg)
4496 {
4497         MonoInst *getaddr, *dummy_use;
4498
4499         if (!cfg->got_var || cfg->got_var_allocated)
4500                 return;
4501
4502         MONO_INST_NEW (cfg, getaddr, OP_LOAD_GOTADDR);
4503         getaddr->cil_code = cfg->header->code;
4504         getaddr->dreg = cfg->got_var->dreg;
4505
4506         /* Add it to the start of the first bblock */
4507         if (cfg->bb_entry->code) {
4508                 getaddr->next = cfg->bb_entry->code;
4509                 cfg->bb_entry->code = getaddr;
4510         }
4511         else
4512                 MONO_ADD_INS (cfg->bb_entry, getaddr);
4513
4514         cfg->got_var_allocated = TRUE;
4515
4516         /* 
4517          * Add a dummy use to keep the got_var alive, since real uses might
4518          * only be generated by the back ends.
4519          * Add it to end_bblock, so the variable's lifetime covers the whole
4520          * method.
4521          * It would be better to make the usage of the got var explicit in all
4522          * cases when the backend needs it (i.e. calls, throw etc.), so this
4523          * wouldn't be needed.
4524          */
4525         NEW_DUMMY_USE (cfg, dummy_use, cfg->got_var);
4526         MONO_ADD_INS (cfg->bb_exit, dummy_use);
4527 }
4528
4529 static int inline_limit;
4530 static gboolean inline_limit_inited;
4531
4532 static gboolean
4533 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
4534 {
4535         MonoMethodHeaderSummary header;
4536         MonoVTable *vtable;
4537 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4538         MonoMethodSignature *sig = mono_method_signature (method);
4539         int i;
4540 #endif
4541
4542         if (cfg->disable_inline)
4543                 return FALSE;
4544         if (cfg->gshared)
4545                 return FALSE;
4546
4547         if (cfg->inline_depth > 10)
4548                 return FALSE;
4549
4550         if (!mono_method_get_header_summary (method, &header))
4551                 return FALSE;
4552
4553         /*runtime, icall and pinvoke are checked by summary call*/
4554         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
4555             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
4556             (mono_class_is_marshalbyref (method->klass)) ||
4557             header.has_clauses)
4558                 return FALSE;
4559
4560         /* also consider num_locals? */
4561         /* Do the size check early to avoid creating vtables */
4562         if (!inline_limit_inited) {
4563                 if (g_getenv ("MONO_INLINELIMIT"))
4564                         inline_limit = atoi (g_getenv ("MONO_INLINELIMIT"));
4565                 else
4566                         inline_limit = INLINE_LENGTH_LIMIT;
4567                 inline_limit_inited = TRUE;
4568         }
4569         if (header.code_size >= inline_limit && !(method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
4570                 return FALSE;
4571
4572         /*
4573          * if we can initialize the class of the method right away, we do,
4574          * otherwise we don't allow inlining if the class needs initialization,
4575          * since it would mean inserting a call to mono_runtime_class_init()
4576          * inside the inlined code
4577          */
4578         if (!(cfg->opt & MONO_OPT_SHARED)) {
4579                 /* The AggressiveInlining hint is a good excuse to force that cctor to run. */
4580                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING) {
4581                         vtable = mono_class_vtable (cfg->domain, method->klass);
4582                         if (!vtable)
4583                                 return FALSE;
4584                         if (!cfg->compile_aot) {
4585                                 MonoError error;
4586                                 if (!mono_runtime_class_init_full (vtable, &error)) {
4587                                         mono_error_cleanup (&error);
4588                                         return FALSE;
4589                                 }
4590                         }
4591                 } else if (mono_class_is_before_field_init (method->klass)) {
4592                         if (cfg->run_cctors && method->klass->has_cctor) {
4593                                 /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
4594                                 if (!method->klass->runtime_info)
4595                                         /* No vtable created yet */
4596                                         return FALSE;
4597                                 vtable = mono_class_vtable (cfg->domain, method->klass);
4598                                 if (!vtable)
4599                                         return FALSE;
4600                                 /* This makes so that inline cannot trigger */
4601                                 /* .cctors: too many apps depend on them */
4602                                 /* running with a specific order... */
4603                                 if (! vtable->initialized)
4604                                         return FALSE;
4605                                 MonoError error;
4606                                 if (!mono_runtime_class_init_full (vtable, &error)) {
4607                                         mono_error_cleanup (&error);
4608                                         return FALSE;
4609                                 }
4610                         }
4611                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
4612                         if (!method->klass->runtime_info)
4613                                 /* No vtable created yet */
4614                                 return FALSE;
4615                         vtable = mono_class_vtable (cfg->domain, method->klass);
4616                         if (!vtable)
4617                                 return FALSE;
4618                         if (!vtable->initialized)
4619                                 return FALSE;
4620                 }
4621         } else {
4622                 /* 
4623                  * If we're compiling for shared code
4624                  * the cctor will need to be run at aot method load time, for example,
4625                  * or at the end of the compilation of the inlining method.
4626                  */
4627                 if (mono_class_needs_cctor_run (method->klass, NULL) && !mono_class_is_before_field_init (method->klass))
4628                         return FALSE;
4629         }
4630
4631 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4632         if (mono_arch_is_soft_float ()) {
4633                 /* FIXME: */
4634                 if (sig->ret && sig->ret->type == MONO_TYPE_R4)
4635                         return FALSE;
4636                 for (i = 0; i < sig->param_count; ++i)
4637                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
4638                                 return FALSE;
4639         }
4640 #endif
4641
4642         if (g_list_find (cfg->dont_inline, method))
4643                 return FALSE;
4644
4645         return TRUE;
4646 }
4647
4648 static gboolean
4649 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoClass *klass, MonoVTable *vtable)
4650 {
4651         if (!cfg->compile_aot) {
4652                 g_assert (vtable);
4653                 if (vtable->initialized)
4654                         return FALSE;
4655         }
4656
4657         if (mono_class_is_before_field_init (klass)) {
4658                 if (cfg->method == method)
4659                         return FALSE;
4660         }
4661
4662         if (!mono_class_needs_cctor_run (klass, method))
4663                 return FALSE;
4664
4665         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (klass == method->klass))
4666                 /* The initialization is already done before the method is called */
4667                 return FALSE;
4668
4669         return TRUE;
4670 }
4671
4672 MonoInst*
4673 mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
4674 {
4675         MonoInst *ins;
4676         guint32 size;
4677         int mult_reg, add_reg, array_reg, index_reg, index2_reg;
4678         int context_used;
4679
4680         if (mini_is_gsharedvt_variable_klass (klass)) {
4681                 size = -1;
4682         } else {
4683                 mono_class_init (klass);
4684                 size = mono_class_array_element_size (klass);
4685         }
4686
4687         mult_reg = alloc_preg (cfg);
4688         array_reg = arr->dreg;
4689         index_reg = index->dreg;
4690
4691 #if SIZEOF_REGISTER == 8
4692         /* The array reg is 64 bits but the index reg is only 32 */
4693         if (COMPILE_LLVM (cfg)) {
4694                 /* Not needed */
4695                 index2_reg = index_reg;
4696         } else {
4697                 index2_reg = alloc_preg (cfg);
4698                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
4699         }
4700 #else
4701         if (index->type == STACK_I8) {
4702                 index2_reg = alloc_preg (cfg);
4703                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I4, index2_reg, index_reg);
4704         } else {
4705                 index2_reg = index_reg;
4706         }
4707 #endif
4708
4709         if (bcheck)
4710                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
4711
4712 #if defined(TARGET_X86) || defined(TARGET_AMD64)
4713         if (size == 1 || size == 2 || size == 4 || size == 8) {
4714                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
4715
4716                 EMIT_NEW_X86_LEA (cfg, ins, array_reg, index2_reg, fast_log2 [size], MONO_STRUCT_OFFSET (MonoArray, vector));
4717                 ins->klass = mono_class_get_element_class (klass);
4718                 ins->type = STACK_MP;
4719
4720                 return ins;
4721         }
4722 #endif          
4723
4724         add_reg = alloc_ireg_mp (cfg);
4725
4726         if (size == -1) {
4727                 MonoInst *rgctx_ins;
4728
4729                 /* gsharedvt */
4730                 g_assert (cfg->gshared);
4731                 context_used = mini_class_check_context_used (cfg, klass);
4732                 g_assert (context_used);
4733                 rgctx_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE);
4734                 MONO_EMIT_NEW_BIALU (cfg, OP_IMUL, mult_reg, index2_reg, rgctx_ins->dreg);
4735         } else {
4736                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
4737         }
4738         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
4739         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
4740         ins->klass = mono_class_get_element_class (klass);
4741         ins->type = STACK_MP;
4742         MONO_ADD_INS (cfg->cbb, ins);
4743
4744         return ins;
4745 }
4746
4747 static MonoInst*
4748 mini_emit_ldelema_2_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index_ins1, MonoInst *index_ins2)
4749 {
4750         int bounds_reg = alloc_preg (cfg);
4751         int add_reg = alloc_ireg_mp (cfg);
4752         int mult_reg = alloc_preg (cfg);
4753         int mult2_reg = alloc_preg (cfg);
4754         int low1_reg = alloc_preg (cfg);
4755         int low2_reg = alloc_preg (cfg);
4756         int high1_reg = alloc_preg (cfg);
4757         int high2_reg = alloc_preg (cfg);
4758         int realidx1_reg = alloc_preg (cfg);
4759         int realidx2_reg = alloc_preg (cfg);
4760         int sum_reg = alloc_preg (cfg);
4761         int index1, index2, tmpreg;
4762         MonoInst *ins;
4763         guint32 size;
4764
4765         mono_class_init (klass);
4766         size = mono_class_array_element_size (klass);
4767
4768         index1 = index_ins1->dreg;
4769         index2 = index_ins2->dreg;
4770
4771 #if SIZEOF_REGISTER == 8
4772         /* The array reg is 64 bits but the index reg is only 32 */
4773         if (COMPILE_LLVM (cfg)) {
4774                 /* Not needed */
4775         } else {
4776                 tmpreg = alloc_preg (cfg);
4777                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index1);
4778                 index1 = tmpreg;
4779                 tmpreg = alloc_preg (cfg);
4780                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index2);
4781                 index2 = tmpreg;
4782         }
4783 #else
4784         // FIXME: Do we need to do something here for i8 indexes, like in ldelema_1_ins ?
4785         tmpreg = -1;
4786 #endif
4787
4788         /* range checking */
4789         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, 
4790                                        arr->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
4791
4792         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low1_reg, 
4793                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
4794         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx1_reg, index1, low1_reg);
4795         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high1_reg, 
4796                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
4797         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high1_reg, realidx1_reg);
4798         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
4799
4800         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low2_reg, 
4801                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
4802         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx2_reg, index2, low2_reg);
4803         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high2_reg, 
4804                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, length));
4805         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high2_reg, realidx2_reg);
4806         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
4807
4808         MONO_EMIT_NEW_BIALU (cfg, OP_PMUL, mult_reg, high2_reg, realidx1_reg);
4809         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, mult_reg, realidx2_reg);
4810         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PMUL_IMM, mult2_reg, sum_reg, size);
4811         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult2_reg, arr->dreg);
4812         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
4813
4814         ins->type = STACK_MP;
4815         ins->klass = klass;
4816         MONO_ADD_INS (cfg->cbb, ins);
4817
4818         return ins;
4819 }
4820
4821 static MonoInst*
4822 mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
4823 {
4824         int rank;
4825         MonoInst *addr;
4826         MonoMethod *addr_method;
4827         int element_size;
4828         MonoClass *eclass = cmethod->klass->element_class;
4829
4830         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
4831
4832         if (rank == 1)
4833                 return mini_emit_ldelema_1_ins (cfg, eclass, sp [0], sp [1], TRUE);
4834
4835         /* emit_ldelema_2 depends on OP_LMUL */
4836         if (!cfg->backend->emulate_mul_div && rank == 2 && (cfg->opt & MONO_OPT_INTRINS) && !mini_is_gsharedvt_variable_klass (eclass)) {
4837                 return mini_emit_ldelema_2_ins (cfg, eclass, sp [0], sp [1], sp [2]);
4838         }
4839
4840         if (mini_is_gsharedvt_variable_klass (eclass))
4841                 element_size = 0;
4842         else
4843                 element_size = mono_class_array_element_size (eclass);
4844         addr_method = mono_marshal_get_array_address (rank, element_size);
4845         addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
4846
4847         return addr;
4848 }
4849
4850 static MonoBreakPolicy
4851 always_insert_breakpoint (MonoMethod *method)
4852 {
4853         return MONO_BREAK_POLICY_ALWAYS;
4854 }
4855
4856 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
4857
4858 /**
4859  * mono_set_break_policy:
4860  * policy_callback: the new callback function
4861  *
4862  * Allow embedders to decide wherther to actually obey breakpoint instructions
4863  * (both break IL instructions and Debugger.Break () method calls), for example
4864  * to not allow an app to be aborted by a perfectly valid IL opcode when executing
4865  * untrusted or semi-trusted code.
4866  *
4867  * @policy_callback will be called every time a break point instruction needs to
4868  * be inserted with the method argument being the method that calls Debugger.Break()
4869  * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
4870  * if it wants the breakpoint to not be effective in the given method.
4871  * #MONO_BREAK_POLICY_ALWAYS is the default.
4872  */
4873 void
4874 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
4875 {
4876         if (policy_callback)
4877                 break_policy_func = policy_callback;
4878         else
4879                 break_policy_func = always_insert_breakpoint;
4880 }
4881
4882 static gboolean
4883 should_insert_brekpoint (MonoMethod *method) {
4884         switch (break_policy_func (method)) {
4885         case MONO_BREAK_POLICY_ALWAYS:
4886                 return TRUE;
4887         case MONO_BREAK_POLICY_NEVER:
4888                 return FALSE;
4889         case MONO_BREAK_POLICY_ON_DBG:
4890                 g_warning ("mdb no longer supported");
4891                 return FALSE;
4892         default:
4893                 g_warning ("Incorrect value returned from break policy callback");
4894                 return FALSE;
4895         }
4896 }
4897
4898 /* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
4899 static MonoInst*
4900 emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
4901 {
4902         MonoInst *addr, *store, *load;
4903         MonoClass *eklass = mono_class_from_mono_type (fsig->params [2]);
4904
4905         /* the bounds check is already done by the callers */
4906         addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
4907         if (is_set) {
4908                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
4909                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
4910                 if (mini_type_is_reference (&eklass->byval_arg))
4911                         emit_write_barrier (cfg, addr, load);
4912         } else {
4913                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
4914                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
4915         }
4916         return store;
4917 }
4918
4919
4920 static gboolean
4921 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
4922 {
4923         return mini_type_is_reference (&klass->byval_arg);
4924 }
4925
4926 static MonoInst*
4927 emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean safety_checks)
4928 {
4929         if (safety_checks && generic_class_is_reference_type (cfg, klass) &&
4930                 !(MONO_INS_IS_PCONST_NULL (sp [2]))) {
4931                 MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
4932                 MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
4933                 MonoInst *iargs [3];
4934
4935                 if (!helper->slot)
4936                         mono_class_setup_vtable (obj_array);
4937                 g_assert (helper->slot);
4938
4939                 if (sp [0]->type != STACK_OBJ)
4940                         return NULL;
4941                 if (sp [2]->type != STACK_OBJ)
4942                         return NULL;
4943
4944                 iargs [2] = sp [2];
4945                 iargs [1] = sp [1];
4946                 iargs [0] = sp [0];
4947
4948                 return mono_emit_method_call (cfg, helper, iargs, sp [0]);
4949         } else {
4950                 MonoInst *ins;
4951
4952                 if (mini_is_gsharedvt_variable_klass (klass)) {
4953                         MonoInst *addr;
4954
4955                         // FIXME-VT: OP_ICONST optimization
4956                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
4957                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
4958                         ins->opcode = OP_STOREV_MEMBASE;
4959                 } else if (sp [1]->opcode == OP_ICONST) {
4960                         int array_reg = sp [0]->dreg;
4961                         int index_reg = sp [1]->dreg;
4962                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
4963
4964                         if (SIZEOF_REGISTER == 8 && COMPILE_LLVM (cfg))
4965                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, index_reg);
4966
4967                         if (safety_checks)
4968                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
4969                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
4970                 } else {
4971                         MonoInst *addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], safety_checks);
4972                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
4973                         if (generic_class_is_reference_type (cfg, klass))
4974                                 emit_write_barrier (cfg, addr, sp [2]);
4975                 }
4976                 return ins;
4977         }
4978 }
4979
4980 static MonoInst*
4981 emit_array_unsafe_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
4982 {
4983         MonoClass *eklass;
4984         
4985         if (is_set)
4986                 eklass = mono_class_from_mono_type (fsig->params [2]);
4987         else
4988                 eklass = mono_class_from_mono_type (fsig->ret);
4989
4990         if (is_set) {
4991                 return emit_array_store (cfg, eklass, args, FALSE);
4992         } else {
4993                 MonoInst *ins, *addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
4994                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &eklass->byval_arg, addr->dreg, 0);
4995                 return ins;
4996         }
4997 }
4998
4999 static gboolean
5000 is_unsafe_mov_compatible (MonoCompile *cfg, MonoClass *param_klass, MonoClass *return_klass)
5001 {
5002         uint32_t align;
5003         int param_size, return_size;
5004
5005         param_klass = mono_class_from_mono_type (mini_get_underlying_type (&param_klass->byval_arg));
5006         return_klass = mono_class_from_mono_type (mini_get_underlying_type (&return_klass->byval_arg));
5007
5008         if (cfg->verbose_level > 3)
5009                 printf ("[UNSAFE-MOV-INTRISIC] %s <- %s\n", return_klass->name, param_klass->name);
5010
5011         //Don't allow mixing reference types with value types
5012         if (param_klass->valuetype != return_klass->valuetype) {
5013                 if (cfg->verbose_level > 3)
5014                         printf ("[UNSAFE-MOV-INTRISIC]\tone of the args is a valuetype and the other is not\n");
5015                 return FALSE;
5016         }
5017
5018         if (!param_klass->valuetype) {
5019                 if (cfg->verbose_level > 3)
5020                         printf ("[UNSAFE-MOV-INTRISIC]\targs are reference types\n");
5021                 return TRUE;
5022         }
5023
5024         //That are blitable
5025         if (param_klass->has_references || return_klass->has_references)
5026                 return FALSE;
5027
5028         /* Avoid mixing structs and primitive types/enums, they need to be handled differently in the JIT */
5029         if ((MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && !MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)) ||
5030                 (!MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && MONO_TYPE_ISSTRUCT (&return_klass->byval_arg))) {
5031                         if (cfg->verbose_level > 3)
5032                                 printf ("[UNSAFE-MOV-INTRISIC]\tmixing structs and scalars\n");
5033                 return FALSE;
5034         }
5035
5036         if (param_klass->byval_arg.type == MONO_TYPE_R4 || param_klass->byval_arg.type == MONO_TYPE_R8 ||
5037                 return_klass->byval_arg.type == MONO_TYPE_R4 || return_klass->byval_arg.type == MONO_TYPE_R8) {
5038                 if (cfg->verbose_level > 3)
5039                         printf ("[UNSAFE-MOV-INTRISIC]\tfloat or double are not supported\n");
5040                 return FALSE;
5041         }
5042
5043         param_size = mono_class_value_size (param_klass, &align);
5044         return_size = mono_class_value_size (return_klass, &align);
5045
5046         //We can do it if sizes match
5047         if (param_size == return_size) {
5048                 if (cfg->verbose_level > 3)
5049                         printf ("[UNSAFE-MOV-INTRISIC]\tsame size\n");
5050                 return TRUE;
5051         }
5052
5053         //No simple way to handle struct if sizes don't match
5054         if (MONO_TYPE_ISSTRUCT (&param_klass->byval_arg)) {
5055                 if (cfg->verbose_level > 3)
5056                         printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch and type is a struct\n");
5057                 return FALSE;
5058         }
5059
5060         /*
5061          * Same reg size category.
5062          * A quick note on why we don't require widening here.
5063          * The intrinsic is "R Array.UnsafeMov<S,R> (S s)".
5064          *
5065          * Since the source value comes from a function argument, the JIT will already have
5066          * the value in a VREG and performed any widening needed before (say, when loading from a field).
5067          */
5068         if (param_size <= 4 && return_size <= 4) {
5069                 if (cfg->verbose_level > 3)
5070                         printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch but both are of the same reg class\n");
5071                 return TRUE;
5072         }
5073
5074         return FALSE;
5075 }
5076
5077 static MonoInst*
5078 emit_array_unsafe_mov (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args)
5079 {
5080         MonoClass *param_klass = mono_class_from_mono_type (fsig->params [0]);
5081         MonoClass *return_klass = mono_class_from_mono_type (fsig->ret);
5082
5083         if (mini_is_gsharedvt_variable_type (fsig->ret))
5084                 return NULL;
5085
5086         //Valuetypes that are semantically equivalent or numbers than can be widened to
5087         if (is_unsafe_mov_compatible (cfg, param_klass, return_klass))
5088                 return args [0];
5089
5090         //Arrays of valuetypes that are semantically equivalent
5091         if (param_klass->rank == 1 && return_klass->rank == 1 && is_unsafe_mov_compatible (cfg, param_klass->element_class, return_klass->element_class))
5092                 return args [0];
5093
5094         return NULL;
5095 }
5096
5097 static MonoInst*
5098 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5099 {
5100 #ifdef MONO_ARCH_SIMD_INTRINSICS
5101         MonoInst *ins = NULL;
5102
5103         if (cfg->opt & MONO_OPT_SIMD) {
5104                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5105                 if (ins)
5106                         return ins;
5107         }
5108 #endif
5109
5110         return mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5111 }
5112
5113 static MonoInst*
5114 emit_memory_barrier (MonoCompile *cfg, int kind)
5115 {
5116         MonoInst *ins = NULL;
5117         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
5118         MONO_ADD_INS (cfg->cbb, ins);
5119         ins->backend.memory_barrier_kind = kind;
5120
5121         return ins;
5122 }
5123
5124 static MonoInst*
5125 llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5126 {
5127         MonoInst *ins = NULL;
5128         int opcode = 0;
5129
5130         /* The LLVM backend supports these intrinsics */
5131         if (cmethod->klass == mono_defaults.math_class) {
5132                 if (strcmp (cmethod->name, "Sin") == 0) {
5133                         opcode = OP_SIN;
5134                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5135                         opcode = OP_COS;
5136                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
5137                         opcode = OP_SQRT;
5138                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5139                         opcode = OP_ABS;
5140                 }
5141
5142                 if (opcode && fsig->param_count == 1) {
5143                         MONO_INST_NEW (cfg, ins, opcode);
5144                         ins->type = STACK_R8;
5145                         ins->dreg = mono_alloc_dreg (cfg, ins->type);
5146                         ins->sreg1 = args [0]->dreg;
5147                         MONO_ADD_INS (cfg->cbb, ins);
5148                 }
5149
5150                 opcode = 0;
5151                 if (cfg->opt & MONO_OPT_CMOV) {
5152                         if (strcmp (cmethod->name, "Min") == 0) {
5153                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5154                                         opcode = OP_IMIN;
5155                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5156                                         opcode = OP_IMIN_UN;
5157                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5158                                         opcode = OP_LMIN;
5159                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5160                                         opcode = OP_LMIN_UN;
5161                         } else if (strcmp (cmethod->name, "Max") == 0) {
5162                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5163                                         opcode = OP_IMAX;
5164                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5165                                         opcode = OP_IMAX_UN;
5166                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5167                                         opcode = OP_LMAX;
5168                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5169                                         opcode = OP_LMAX_UN;
5170                         }
5171                 }
5172
5173                 if (opcode && fsig->param_count == 2) {
5174                         MONO_INST_NEW (cfg, ins, opcode);
5175                         ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
5176                         ins->dreg = mono_alloc_dreg (cfg, ins->type);
5177                         ins->sreg1 = args [0]->dreg;
5178                         ins->sreg2 = args [1]->dreg;
5179                         MONO_ADD_INS (cfg->cbb, ins);
5180                 }
5181         }
5182
5183         return ins;
5184 }
5185
5186 static MonoInst*
5187 mini_emit_inst_for_sharable_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5188 {
5189         if (cmethod->klass == mono_defaults.array_class) {
5190                 if (strcmp (cmethod->name, "UnsafeStore") == 0)
5191                         return emit_array_unsafe_access (cfg, fsig, args, TRUE);
5192                 else if (strcmp (cmethod->name, "UnsafeLoad") == 0)
5193                         return emit_array_unsafe_access (cfg, fsig, args, FALSE);
5194                 else if (strcmp (cmethod->name, "UnsafeMov") == 0)
5195                         return emit_array_unsafe_mov (cfg, fsig, args);
5196         }
5197
5198         return NULL;
5199 }
5200
5201 static MonoInst*
5202 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5203 {
5204         MonoInst *ins = NULL;
5205
5206          MonoClass *runtime_helpers_class = mono_class_get_runtime_helpers_class ();
5207
5208         if (cmethod->klass == mono_defaults.string_class) {
5209                 if (strcmp (cmethod->name, "get_Chars") == 0 && fsig->param_count + fsig->hasthis == 2) {
5210                         int dreg = alloc_ireg (cfg);
5211                         int index_reg = alloc_preg (cfg);
5212                         int add_reg = alloc_preg (cfg);
5213
5214 #if SIZEOF_REGISTER == 8
5215                         if (COMPILE_LLVM (cfg)) {
5216                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, args [1]->dreg);
5217                         } else {
5218                                 /* The array reg is 64 bits but the index reg is only 32 */
5219                                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
5220                         }
5221 #else
5222                         index_reg = args [1]->dreg;
5223 #endif  
5224                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
5225
5226 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5227                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, MONO_STRUCT_OFFSET (MonoString, chars));
5228                         add_reg = ins->dreg;
5229                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5230                                                                    add_reg, 0);
5231 #else
5232                         int mult_reg = alloc_preg (cfg);
5233                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
5234                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5235                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5236                                                                    add_reg, MONO_STRUCT_OFFSET (MonoString, chars));
5237 #endif
5238                         type_from_op (cfg, ins, NULL, NULL);
5239                         return ins;
5240                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
5241                         int dreg = alloc_ireg (cfg);
5242                         /* Decompose later to allow more optimizations */
5243                         EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
5244                         ins->type = STACK_I4;
5245                         ins->flags |= MONO_INST_FAULT;
5246                         cfg->cbb->has_array_access = TRUE;
5247                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
5248
5249                         return ins;
5250                 } else 
5251                         return NULL;
5252         } else if (cmethod->klass == mono_defaults.object_class) {
5253                 if (strcmp (cmethod->name, "GetType") == 0 && fsig->param_count + fsig->hasthis == 1) {
5254                         int dreg = alloc_ireg_ref (cfg);
5255                         int vt_reg = alloc_preg (cfg);
5256                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5257                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, MONO_STRUCT_OFFSET (MonoVTable, type));
5258                         type_from_op (cfg, ins, NULL, NULL);
5259
5260                         return ins;
5261                 } else if (!cfg->backend->emulate_mul_div && strcmp (cmethod->name, "InternalGetHashCode") == 0 && fsig->param_count == 1 && !mono_gc_is_moving ()) {
5262                         int dreg = alloc_ireg (cfg);
5263                         int t1 = alloc_ireg (cfg);
5264         
5265                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
5266                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
5267                         ins->type = STACK_I4;
5268
5269                         return ins;
5270                 } else if (strcmp (cmethod->name, ".ctor") == 0 && fsig->param_count == 0) {
5271                         MONO_INST_NEW (cfg, ins, OP_NOP);
5272                         MONO_ADD_INS (cfg->cbb, ins);
5273                         return ins;
5274                 } else
5275                         return NULL;
5276         } else if (cmethod->klass == mono_defaults.array_class) {
5277                 if (strcmp (cmethod->name, "GetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
5278                         return emit_array_generic_access (cfg, fsig, args, FALSE);
5279                 else if (strcmp (cmethod->name, "SetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
5280                         return emit_array_generic_access (cfg, fsig, args, TRUE);
5281
5282 #ifndef MONO_BIG_ARRAYS
5283                 /*
5284                  * This is an inline version of GetLength/GetLowerBound(0) used frequently in
5285                  * Array methods.
5286                  */
5287                 else if (((strcmp (cmethod->name, "GetLength") == 0 && fsig->param_count + fsig->hasthis == 2) ||
5288                          (strcmp (cmethod->name, "GetLowerBound") == 0 && fsig->param_count + fsig->hasthis == 2)) &&
5289                          args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) {
5290                         int dreg = alloc_ireg (cfg);
5291                         int bounds_reg = alloc_ireg_mp (cfg);
5292                         MonoBasicBlock *end_bb, *szarray_bb;
5293                         gboolean get_length = strcmp (cmethod->name, "GetLength") == 0;
5294
5295                         NEW_BBLOCK (cfg, end_bb);
5296                         NEW_BBLOCK (cfg, szarray_bb);
5297
5298                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOAD_MEMBASE, bounds_reg,
5299                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5300                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
5301                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, szarray_bb);
5302                         /* Non-szarray case */
5303                         if (get_length)
5304                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5305                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5306                         else
5307                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5308                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5309                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
5310                         MONO_START_BB (cfg, szarray_bb);
5311                         /* Szarray case */
5312                         if (get_length)
5313                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5314                                                                            args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
5315                         else
5316                                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
5317                         MONO_START_BB (cfg, end_bb);
5318
5319                         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg);
5320                         ins->type = STACK_I4;
5321                         
5322                         return ins;
5323                 }
5324 #endif
5325
5326                 if (cmethod->name [0] != 'g')
5327                         return NULL;
5328
5329                 if (strcmp (cmethod->name, "get_Rank") == 0 && fsig->param_count + fsig->hasthis == 1) {
5330                         int dreg = alloc_ireg (cfg);
5331                         int vtable_reg = alloc_preg (cfg);
5332                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
5333                                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5334                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
5335                                                                    vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
5336                         type_from_op (cfg, ins, NULL, NULL);
5337
5338                         return ins;
5339                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
5340                         int dreg = alloc_ireg (cfg);
5341
5342                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
5343                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
5344                         type_from_op (cfg, ins, NULL, NULL);
5345
5346                         return ins;
5347                 } else
5348                         return NULL;
5349         } else if (cmethod->klass == runtime_helpers_class) {
5350                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0 && fsig->param_count == 0) {
5351                         EMIT_NEW_ICONST (cfg, ins, MONO_STRUCT_OFFSET (MonoString, chars));
5352                         return ins;
5353                 } else
5354                         return NULL;
5355         } else if (cmethod->klass == mono_defaults.monitor_class) {
5356                 gboolean is_enter = FALSE;
5357                 gboolean is_v4 = FALSE;
5358
5359                 if (!strcmp (cmethod->name, "Enter") && fsig->param_count == 2 && fsig->params [1]->byref) {
5360                         is_enter = TRUE;
5361                         is_v4 = TRUE;
5362                 }
5363                 if (!strcmp (cmethod->name, "Enter") && fsig->param_count == 1)
5364                         is_enter = TRUE;
5365
5366                 if (is_enter) {
5367                         /*
5368                          * To make async stack traces work, icalls which can block should have a wrapper.
5369                          * For Monitor.Enter, emit two calls: a fastpath which doesn't have a wrapper, and a slowpath, which does.
5370                          */
5371                         MonoBasicBlock *end_bb;
5372
5373                         NEW_BBLOCK (cfg, end_bb);
5374
5375                         ins = mono_emit_jit_icall (cfg, is_v4 ? (gpointer)mono_monitor_enter_v4_fast : (gpointer)mono_monitor_enter_fast, args);
5376                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, ins->dreg, 0);
5377                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, end_bb);
5378                         ins = mono_emit_jit_icall (cfg, is_v4 ? (gpointer)mono_monitor_enter_v4 : (gpointer)mono_monitor_enter, args);
5379                         MONO_START_BB (cfg, end_bb);
5380                         return ins;
5381                 }
5382         } else if (cmethod->klass == mono_defaults.thread_class) {
5383                 if (strcmp (cmethod->name, "SpinWait_nop") == 0 && fsig->param_count == 0) {
5384                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
5385                         MONO_ADD_INS (cfg->cbb, ins);
5386                         return ins;
5387                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0) {
5388                         return emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5389                 } else if (!strcmp (cmethod->name, "VolatileRead") && fsig->param_count == 1) {
5390                         guint32 opcode = 0;
5391                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
5392
5393                         if (fsig->params [0]->type == MONO_TYPE_I1)
5394                                 opcode = OP_LOADI1_MEMBASE;
5395                         else if (fsig->params [0]->type == MONO_TYPE_U1)
5396                                 opcode = OP_LOADU1_MEMBASE;
5397                         else if (fsig->params [0]->type == MONO_TYPE_I2)
5398                                 opcode = OP_LOADI2_MEMBASE;
5399                         else if (fsig->params [0]->type == MONO_TYPE_U2)
5400                                 opcode = OP_LOADU2_MEMBASE;
5401                         else if (fsig->params [0]->type == MONO_TYPE_I4)
5402                                 opcode = OP_LOADI4_MEMBASE;
5403                         else if (fsig->params [0]->type == MONO_TYPE_U4)
5404                                 opcode = OP_LOADU4_MEMBASE;
5405                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
5406                                 opcode = OP_LOADI8_MEMBASE;
5407                         else if (fsig->params [0]->type == MONO_TYPE_R4)
5408                                 opcode = OP_LOADR4_MEMBASE;
5409                         else if (fsig->params [0]->type == MONO_TYPE_R8)
5410                                 opcode = OP_LOADR8_MEMBASE;
5411                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
5412                                 opcode = OP_LOAD_MEMBASE;
5413
5414                         if (opcode) {
5415                                 MONO_INST_NEW (cfg, ins, opcode);
5416                                 ins->inst_basereg = args [0]->dreg;
5417                                 ins->inst_offset = 0;
5418                                 MONO_ADD_INS (cfg->cbb, ins);
5419
5420                                 switch (fsig->params [0]->type) {
5421                                 case MONO_TYPE_I1:
5422                                 case MONO_TYPE_U1:
5423                                 case MONO_TYPE_I2:
5424                                 case MONO_TYPE_U2:
5425                                 case MONO_TYPE_I4:
5426                                 case MONO_TYPE_U4:
5427                                         ins->dreg = mono_alloc_ireg (cfg);
5428                                         ins->type = STACK_I4;
5429                                         break;
5430                                 case MONO_TYPE_I8:
5431                                 case MONO_TYPE_U8:
5432                                         ins->dreg = mono_alloc_lreg (cfg);
5433                                         ins->type = STACK_I8;
5434                                         break;
5435                                 case MONO_TYPE_I:
5436                                 case MONO_TYPE_U:
5437                                         ins->dreg = mono_alloc_ireg (cfg);
5438 #if SIZEOF_REGISTER == 8
5439                                         ins->type = STACK_I8;
5440 #else
5441                                         ins->type = STACK_I4;
5442 #endif
5443                                         break;
5444                                 case MONO_TYPE_R4:
5445                                 case MONO_TYPE_R8:
5446                                         ins->dreg = mono_alloc_freg (cfg);
5447                                         ins->type = STACK_R8;
5448                                         break;
5449                                 default:
5450                                         g_assert (mini_type_is_reference (fsig->params [0]));
5451                                         ins->dreg = mono_alloc_ireg_ref (cfg);
5452                                         ins->type = STACK_OBJ;
5453                                         break;
5454                                 }
5455
5456                                 if (opcode == OP_LOADI8_MEMBASE)
5457                                         ins = mono_decompose_opcode (cfg, ins);
5458
5459                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5460
5461                                 return ins;
5462                         }
5463                 } else if (!strcmp (cmethod->name, "VolatileWrite") && fsig->param_count == 2) {
5464                         guint32 opcode = 0;
5465                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
5466
5467                         if (fsig->params [0]->type == MONO_TYPE_I1 || fsig->params [0]->type == MONO_TYPE_U1)
5468                                 opcode = OP_STOREI1_MEMBASE_REG;
5469                         else if (fsig->params [0]->type == MONO_TYPE_I2 || fsig->params [0]->type == MONO_TYPE_U2)
5470                                 opcode = OP_STOREI2_MEMBASE_REG;
5471                         else if (fsig->params [0]->type == MONO_TYPE_I4 || fsig->params [0]->type == MONO_TYPE_U4)
5472                                 opcode = OP_STOREI4_MEMBASE_REG;
5473                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
5474                                 opcode = OP_STOREI8_MEMBASE_REG;
5475                         else if (fsig->params [0]->type == MONO_TYPE_R4)
5476                                 opcode = OP_STORER4_MEMBASE_REG;
5477                         else if (fsig->params [0]->type == MONO_TYPE_R8)
5478                                 opcode = OP_STORER8_MEMBASE_REG;
5479                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
5480                                 opcode = OP_STORE_MEMBASE_REG;
5481
5482                         if (opcode) {
5483                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5484
5485                                 MONO_INST_NEW (cfg, ins, opcode);
5486                                 ins->sreg1 = args [1]->dreg;
5487                                 ins->inst_destbasereg = args [0]->dreg;
5488                                 ins->inst_offset = 0;
5489                                 MONO_ADD_INS (cfg->cbb, ins);
5490
5491                                 if (opcode == OP_STOREI8_MEMBASE_REG)
5492                                         ins = mono_decompose_opcode (cfg, ins);
5493
5494                                 return ins;
5495                         }
5496                 }
5497         } else if (cmethod->klass->image == mono_defaults.corlib &&
5498                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
5499                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
5500                 ins = NULL;
5501
5502 #if SIZEOF_REGISTER == 8
5503                 if (!cfg->llvm_only && strcmp (cmethod->name, "Read") == 0 && fsig->param_count == 1 && (fsig->params [0]->type == MONO_TYPE_I8)) {
5504                         if (!cfg->llvm_only && mono_arch_opcode_supported (OP_ATOMIC_LOAD_I8)) {
5505                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_LOAD_I8);
5506                                 ins->dreg = mono_alloc_preg (cfg);
5507                                 ins->sreg1 = args [0]->dreg;
5508                                 ins->type = STACK_I8;
5509                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_SEQ;
5510                                 MONO_ADD_INS (cfg->cbb, ins);
5511                         } else {
5512                                 MonoInst *load_ins;
5513
5514                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5515
5516                                 /* 64 bit reads are already atomic */
5517                                 MONO_INST_NEW (cfg, load_ins, OP_LOADI8_MEMBASE);
5518                                 load_ins->dreg = mono_alloc_preg (cfg);
5519                                 load_ins->inst_basereg = args [0]->dreg;
5520                                 load_ins->inst_offset = 0;
5521                                 load_ins->type = STACK_I8;
5522                                 MONO_ADD_INS (cfg->cbb, load_ins);
5523
5524                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5525
5526                                 ins = load_ins;
5527                         }
5528                 }
5529 #endif
5530
5531                 if (strcmp (cmethod->name, "Increment") == 0 && fsig->param_count == 1) {
5532                         MonoInst *ins_iconst;
5533                         guint32 opcode = 0;
5534
5535                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5536                                 opcode = OP_ATOMIC_ADD_I4;
5537                                 cfg->has_atomic_add_i4 = TRUE;
5538                         }
5539 #if SIZEOF_REGISTER == 8
5540                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5541                                 opcode = OP_ATOMIC_ADD_I8;
5542 #endif
5543                         if (opcode) {
5544                                 if (!mono_arch_opcode_supported (opcode))
5545                                         return NULL;
5546                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
5547                                 ins_iconst->inst_c0 = 1;
5548                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
5549                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
5550
5551                                 MONO_INST_NEW (cfg, ins, opcode);
5552                                 ins->dreg = mono_alloc_ireg (cfg);
5553                                 ins->inst_basereg = args [0]->dreg;
5554                                 ins->inst_offset = 0;
5555                                 ins->sreg2 = ins_iconst->dreg;
5556                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
5557                                 MONO_ADD_INS (cfg->cbb, ins);
5558                         }
5559                 } else if (strcmp (cmethod->name, "Decrement") == 0 && fsig->param_count == 1) {
5560                         MonoInst *ins_iconst;
5561                         guint32 opcode = 0;
5562
5563                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5564                                 opcode = OP_ATOMIC_ADD_I4;
5565                                 cfg->has_atomic_add_i4 = TRUE;
5566                         }
5567 #if SIZEOF_REGISTER == 8
5568                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5569                                 opcode = OP_ATOMIC_ADD_I8;
5570 #endif
5571                         if (opcode) {
5572                                 if (!mono_arch_opcode_supported (opcode))
5573                                         return NULL;
5574                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
5575                                 ins_iconst->inst_c0 = -1;
5576                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
5577                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
5578
5579                                 MONO_INST_NEW (cfg, ins, opcode);
5580                                 ins->dreg = mono_alloc_ireg (cfg);
5581                                 ins->inst_basereg = args [0]->dreg;
5582                                 ins->inst_offset = 0;
5583                                 ins->sreg2 = ins_iconst->dreg;
5584                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
5585                                 MONO_ADD_INS (cfg->cbb, ins);
5586                         }
5587                 } else if (strcmp (cmethod->name, "Add") == 0 && fsig->param_count == 2) {
5588                         guint32 opcode = 0;
5589
5590                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5591                                 opcode = OP_ATOMIC_ADD_I4;
5592                                 cfg->has_atomic_add_i4 = TRUE;
5593                         }
5594 #if SIZEOF_REGISTER == 8
5595                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5596                                 opcode = OP_ATOMIC_ADD_I8;
5597 #endif
5598                         if (opcode) {
5599                                 if (!mono_arch_opcode_supported (opcode))
5600                                         return NULL;
5601                                 MONO_INST_NEW (cfg, ins, opcode);
5602                                 ins->dreg = mono_alloc_ireg (cfg);
5603                                 ins->inst_basereg = args [0]->dreg;
5604                                 ins->inst_offset = 0;
5605                                 ins->sreg2 = args [1]->dreg;
5606                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
5607                                 MONO_ADD_INS (cfg->cbb, ins);
5608                         }
5609                 }
5610                 else if (strcmp (cmethod->name, "Exchange") == 0 && fsig->param_count == 2) {
5611                         MonoInst *f2i = NULL, *i2f;
5612                         guint32 opcode, f2i_opcode, i2f_opcode;
5613                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
5614                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
5615
5616                         if (fsig->params [0]->type == MONO_TYPE_I4 ||
5617                             fsig->params [0]->type == MONO_TYPE_R4) {
5618                                 opcode = OP_ATOMIC_EXCHANGE_I4;
5619                                 f2i_opcode = OP_MOVE_F_TO_I4;
5620                                 i2f_opcode = OP_MOVE_I4_TO_F;
5621                                 cfg->has_atomic_exchange_i4 = TRUE;
5622                         }
5623 #if SIZEOF_REGISTER == 8
5624                         else if (is_ref ||
5625                                  fsig->params [0]->type == MONO_TYPE_I8 ||
5626                                  fsig->params [0]->type == MONO_TYPE_R8 ||
5627                                  fsig->params [0]->type == MONO_TYPE_I) {
5628                                 opcode = OP_ATOMIC_EXCHANGE_I8;
5629                                 f2i_opcode = OP_MOVE_F_TO_I8;
5630                                 i2f_opcode = OP_MOVE_I8_TO_F;
5631                         }
5632 #else
5633                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I) {
5634                                 opcode = OP_ATOMIC_EXCHANGE_I4;
5635                                 cfg->has_atomic_exchange_i4 = TRUE;
5636                         }
5637 #endif
5638                         else
5639                                 return NULL;
5640
5641                         if (!mono_arch_opcode_supported (opcode))
5642                                 return NULL;
5643
5644                         if (is_float) {
5645                                 /* TODO: Decompose these opcodes instead of bailing here. */
5646                                 if (COMPILE_SOFT_FLOAT (cfg))
5647                                         return NULL;
5648
5649                                 MONO_INST_NEW (cfg, f2i, f2i_opcode);
5650                                 f2i->dreg = mono_alloc_ireg (cfg);
5651                                 f2i->sreg1 = args [1]->dreg;
5652                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
5653                                         f2i->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
5654                                 MONO_ADD_INS (cfg->cbb, f2i);
5655                         }
5656
5657                         MONO_INST_NEW (cfg, ins, opcode);
5658                         ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg);
5659                         ins->inst_basereg = args [0]->dreg;
5660                         ins->inst_offset = 0;
5661                         ins->sreg2 = is_float ? f2i->dreg : args [1]->dreg;
5662                         MONO_ADD_INS (cfg->cbb, ins);
5663
5664                         switch (fsig->params [0]->type) {
5665                         case MONO_TYPE_I4:
5666                                 ins->type = STACK_I4;
5667                                 break;
5668                         case MONO_TYPE_I8:
5669                                 ins->type = STACK_I8;
5670                                 break;
5671                         case MONO_TYPE_I:
5672 #if SIZEOF_REGISTER == 8
5673                                 ins->type = STACK_I8;
5674 #else
5675                                 ins->type = STACK_I4;
5676 #endif
5677                                 break;
5678                         case MONO_TYPE_R4:
5679                         case MONO_TYPE_R8:
5680                                 ins->type = STACK_R8;
5681                                 break;
5682                         default:
5683                                 g_assert (mini_type_is_reference (fsig->params [0]));
5684                                 ins->type = STACK_OBJ;
5685                                 break;
5686                         }
5687
5688                         if (is_float) {
5689                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
5690                                 i2f->dreg = mono_alloc_freg (cfg);
5691                                 i2f->sreg1 = ins->dreg;
5692                                 i2f->type = STACK_R8;
5693                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
5694                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
5695                                 MONO_ADD_INS (cfg->cbb, i2f);
5696
5697                                 ins = i2f;
5698                         }
5699
5700                         if (cfg->gen_write_barriers && is_ref)
5701                                 emit_write_barrier (cfg, args [0], args [1]);
5702                 }
5703                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 3) {
5704                         MonoInst *f2i_new = NULL, *f2i_cmp = NULL, *i2f;
5705                         guint32 opcode, f2i_opcode, i2f_opcode;
5706                         gboolean is_ref = mini_type_is_reference (fsig->params [1]);
5707                         gboolean is_float = fsig->params [1]->type == MONO_TYPE_R4 || fsig->params [1]->type == MONO_TYPE_R8;
5708
5709                         if (fsig->params [1]->type == MONO_TYPE_I4 ||
5710                             fsig->params [1]->type == MONO_TYPE_R4) {
5711                                 opcode = OP_ATOMIC_CAS_I4;
5712                                 f2i_opcode = OP_MOVE_F_TO_I4;
5713                                 i2f_opcode = OP_MOVE_I4_TO_F;
5714                                 cfg->has_atomic_cas_i4 = TRUE;
5715                         }
5716 #if SIZEOF_REGISTER == 8
5717                         else if (is_ref ||
5718                                  fsig->params [1]->type == MONO_TYPE_I8 ||
5719                                  fsig->params [1]->type == MONO_TYPE_R8 ||
5720                                  fsig->params [1]->type == MONO_TYPE_I) {
5721                                 opcode = OP_ATOMIC_CAS_I8;
5722                                 f2i_opcode = OP_MOVE_F_TO_I8;
5723                                 i2f_opcode = OP_MOVE_I8_TO_F;
5724                         }
5725 #else
5726                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I) {
5727                                 opcode = OP_ATOMIC_CAS_I4;
5728                                 cfg->has_atomic_cas_i4 = TRUE;
5729                         }
5730 #endif
5731                         else
5732                                 return NULL;
5733
5734                         if (!mono_arch_opcode_supported (opcode))
5735                                 return NULL;
5736
5737                         if (is_float) {
5738                                 /* TODO: Decompose these opcodes instead of bailing here. */
5739                                 if (COMPILE_SOFT_FLOAT (cfg))
5740                                         return NULL;
5741
5742                                 MONO_INST_NEW (cfg, f2i_new, f2i_opcode);
5743                                 f2i_new->dreg = mono_alloc_ireg (cfg);
5744                                 f2i_new->sreg1 = args [1]->dreg;
5745                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
5746                                         f2i_new->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
5747                                 MONO_ADD_INS (cfg->cbb, f2i_new);
5748
5749                                 MONO_INST_NEW (cfg, f2i_cmp, f2i_opcode);
5750                                 f2i_cmp->dreg = mono_alloc_ireg (cfg);
5751                                 f2i_cmp->sreg1 = args [2]->dreg;
5752                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
5753                                         f2i_cmp->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
5754                                 MONO_ADD_INS (cfg->cbb, f2i_cmp);
5755                         }
5756
5757                         MONO_INST_NEW (cfg, ins, opcode);
5758                         ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
5759                         ins->sreg1 = args [0]->dreg;
5760                         ins->sreg2 = is_float ? f2i_new->dreg : args [1]->dreg;
5761                         ins->sreg3 = is_float ? f2i_cmp->dreg : args [2]->dreg;
5762                         MONO_ADD_INS (cfg->cbb, ins);
5763
5764                         switch (fsig->params [1]->type) {
5765                         case MONO_TYPE_I4:
5766                                 ins->type = STACK_I4;
5767                                 break;
5768                         case MONO_TYPE_I8:
5769                                 ins->type = STACK_I8;
5770                                 break;
5771                         case MONO_TYPE_I:
5772 #if SIZEOF_REGISTER == 8
5773                                 ins->type = STACK_I8;
5774 #else
5775                                 ins->type = STACK_I4;
5776 #endif
5777                                 break;
5778                         case MONO_TYPE_R4:
5779                                 ins->type = cfg->r4_stack_type;
5780                                 break;
5781                         case MONO_TYPE_R8:
5782                                 ins->type = STACK_R8;
5783                                 break;
5784                         default:
5785                                 g_assert (mini_type_is_reference (fsig->params [1]));
5786                                 ins->type = STACK_OBJ;
5787                                 break;
5788                         }
5789
5790                         if (is_float) {
5791                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
5792                                 i2f->dreg = mono_alloc_freg (cfg);
5793                                 i2f->sreg1 = ins->dreg;
5794                                 i2f->type = STACK_R8;
5795                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
5796                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
5797                                 MONO_ADD_INS (cfg->cbb, i2f);
5798
5799                                 ins = i2f;
5800                         }
5801
5802                         if (cfg->gen_write_barriers && is_ref)
5803                                 emit_write_barrier (cfg, args [0], args [1]);
5804                 }
5805                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 4 &&
5806                          fsig->params [1]->type == MONO_TYPE_I4) {
5807                         MonoInst *cmp, *ceq;
5808
5809                         if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I4))
5810                                 return NULL;
5811
5812                         /* int32 r = CAS (location, value, comparand); */
5813                         MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
5814                         ins->dreg = alloc_ireg (cfg);
5815                         ins->sreg1 = args [0]->dreg;
5816                         ins->sreg2 = args [1]->dreg;
5817                         ins->sreg3 = args [2]->dreg;
5818                         ins->type = STACK_I4;
5819                         MONO_ADD_INS (cfg->cbb, ins);
5820
5821                         /* bool result = r == comparand; */
5822                         MONO_INST_NEW (cfg, cmp, OP_ICOMPARE);
5823                         cmp->sreg1 = ins->dreg;
5824                         cmp->sreg2 = args [2]->dreg;
5825                         cmp->type = STACK_I4;
5826                         MONO_ADD_INS (cfg->cbb, cmp);
5827
5828                         MONO_INST_NEW (cfg, ceq, OP_ICEQ);
5829                         ceq->dreg = alloc_ireg (cfg);
5830                         ceq->type = STACK_I4;
5831                         MONO_ADD_INS (cfg->cbb, ceq);
5832
5833                         /* *success = result; */
5834                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, args [3]->dreg, 0, ceq->dreg);
5835
5836                         cfg->has_atomic_cas_i4 = TRUE;
5837                 }
5838                 else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0)
5839                         ins = emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5840
5841                 if (ins)
5842                         return ins;
5843         } else if (cmethod->klass->image == mono_defaults.corlib &&
5844                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
5845                            (strcmp (cmethod->klass->name, "Volatile") == 0)) {
5846                 ins = NULL;
5847
5848                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Read") && fsig->param_count == 1) {
5849                         guint32 opcode = 0;
5850                         MonoType *t = fsig->params [0];
5851                         gboolean is_ref;
5852                         gboolean is_float = t->type == MONO_TYPE_R4 || t->type == MONO_TYPE_R8;
5853
5854                         g_assert (t->byref);
5855                         /* t is a byref type, so the reference check is more complicated */
5856                         is_ref = mini_type_is_reference (&mono_class_from_mono_type (t)->byval_arg);
5857                         if (t->type == MONO_TYPE_I1)
5858                                 opcode = OP_ATOMIC_LOAD_I1;
5859                         else if (t->type == MONO_TYPE_U1 || t->type == MONO_TYPE_BOOLEAN)
5860                                 opcode = OP_ATOMIC_LOAD_U1;
5861                         else if (t->type == MONO_TYPE_I2)
5862                                 opcode = OP_ATOMIC_LOAD_I2;
5863                         else if (t->type == MONO_TYPE_U2)
5864                                 opcode = OP_ATOMIC_LOAD_U2;
5865                         else if (t->type == MONO_TYPE_I4)
5866                                 opcode = OP_ATOMIC_LOAD_I4;
5867                         else if (t->type == MONO_TYPE_U4)
5868                                 opcode = OP_ATOMIC_LOAD_U4;
5869                         else if (t->type == MONO_TYPE_R4)
5870                                 opcode = OP_ATOMIC_LOAD_R4;
5871                         else if (t->type == MONO_TYPE_R8)
5872                                 opcode = OP_ATOMIC_LOAD_R8;
5873 #if SIZEOF_REGISTER == 8
5874                         else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_I)
5875                                 opcode = OP_ATOMIC_LOAD_I8;
5876                         else if (is_ref || t->type == MONO_TYPE_U8 || t->type == MONO_TYPE_U)
5877                                 opcode = OP_ATOMIC_LOAD_U8;
5878 #else
5879                         else if (t->type == MONO_TYPE_I)
5880                                 opcode = OP_ATOMIC_LOAD_I4;
5881                         else if (is_ref || t->type == MONO_TYPE_U)
5882                                 opcode = OP_ATOMIC_LOAD_U4;
5883 #endif
5884
5885                         if (opcode) {
5886                                 if (!mono_arch_opcode_supported (opcode))
5887                                         return NULL;
5888
5889                                 MONO_INST_NEW (cfg, ins, opcode);
5890                                 ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : (is_float ? mono_alloc_freg (cfg) : mono_alloc_ireg (cfg));
5891                                 ins->sreg1 = args [0]->dreg;
5892                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_ACQ;
5893                                 MONO_ADD_INS (cfg->cbb, ins);
5894
5895                                 switch (t->type) {
5896                                 case MONO_TYPE_BOOLEAN:
5897                                 case MONO_TYPE_I1:
5898                                 case MONO_TYPE_U1:
5899                                 case MONO_TYPE_I2:
5900                                 case MONO_TYPE_U2:
5901                                 case MONO_TYPE_I4:
5902                                 case MONO_TYPE_U4:
5903                                         ins->type = STACK_I4;
5904                                         break;
5905                                 case MONO_TYPE_I8:
5906                                 case MONO_TYPE_U8:
5907                                         ins->type = STACK_I8;
5908                                         break;
5909                                 case MONO_TYPE_I:
5910                                 case MONO_TYPE_U:
5911 #if SIZEOF_REGISTER == 8
5912                                         ins->type = STACK_I8;
5913 #else
5914                                         ins->type = STACK_I4;
5915 #endif
5916                                         break;
5917                                 case MONO_TYPE_R4:
5918                                         ins->type = cfg->r4_stack_type;
5919                                         break;
5920                                 case MONO_TYPE_R8:
5921                                         ins->type = STACK_R8;
5922                                         break;
5923                                 default:
5924                                         g_assert (is_ref);
5925                                         ins->type = STACK_OBJ;
5926                                         break;
5927                                 }
5928                         }
5929                 }
5930
5931                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Write") && fsig->param_count == 2) {
5932                         guint32 opcode = 0;
5933                         MonoType *t = fsig->params [0];
5934                         gboolean is_ref;
5935
5936                         g_assert (t->byref);
5937                         is_ref = mini_type_is_reference (&mono_class_from_mono_type (t)->byval_arg);
5938                         if (t->type == MONO_TYPE_I1)
5939                                 opcode = OP_ATOMIC_STORE_I1;
5940                         else if (t->type == MONO_TYPE_U1 || t->type == MONO_TYPE_BOOLEAN)
5941                                 opcode = OP_ATOMIC_STORE_U1;
5942                         else if (t->type == MONO_TYPE_I2)
5943                                 opcode = OP_ATOMIC_STORE_I2;
5944                         else if (t->type == MONO_TYPE_U2)
5945                                 opcode = OP_ATOMIC_STORE_U2;
5946                         else if (t->type == MONO_TYPE_I4)
5947                                 opcode = OP_ATOMIC_STORE_I4;
5948                         else if (t->type == MONO_TYPE_U4)
5949                                 opcode = OP_ATOMIC_STORE_U4;
5950                         else if (t->type == MONO_TYPE_R4)
5951                                 opcode = OP_ATOMIC_STORE_R4;
5952                         else if (t->type == MONO_TYPE_R8)
5953                                 opcode = OP_ATOMIC_STORE_R8;
5954 #if SIZEOF_REGISTER == 8
5955                         else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_I)
5956                                 opcode = OP_ATOMIC_STORE_I8;
5957                         else if (is_ref || t->type == MONO_TYPE_U8 || t->type == MONO_TYPE_U)
5958                                 opcode = OP_ATOMIC_STORE_U8;
5959 #else
5960                         else if (t->type == MONO_TYPE_I)
5961                                 opcode = OP_ATOMIC_STORE_I4;
5962                         else if (is_ref || t->type == MONO_TYPE_U)
5963                                 opcode = OP_ATOMIC_STORE_U4;
5964 #endif
5965
5966                         if (opcode) {
5967                                 if (!mono_arch_opcode_supported (opcode))
5968                                         return NULL;
5969
5970                                 MONO_INST_NEW (cfg, ins, opcode);
5971                                 ins->dreg = args [0]->dreg;
5972                                 ins->sreg1 = args [1]->dreg;
5973                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_REL;
5974                                 MONO_ADD_INS (cfg->cbb, ins);
5975
5976                                 if (cfg->gen_write_barriers && is_ref)
5977                                         emit_write_barrier (cfg, args [0], args [1]);
5978                         }
5979                 }
5980
5981                 if (ins)
5982                         return ins;
5983         } else if (cmethod->klass->image == mono_defaults.corlib &&
5984                            (strcmp (cmethod->klass->name_space, "System.Diagnostics") == 0) &&
5985                            (strcmp (cmethod->klass->name, "Debugger") == 0)) {
5986                 if (!strcmp (cmethod->name, "Break") && fsig->param_count == 0) {
5987                         if (should_insert_brekpoint (cfg->method)) {
5988                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
5989                         } else {
5990                                 MONO_INST_NEW (cfg, ins, OP_NOP);
5991                                 MONO_ADD_INS (cfg->cbb, ins);
5992                         }
5993                         return ins;
5994                 }
5995         } else if (cmethod->klass->image == mono_defaults.corlib &&
5996                    (strcmp (cmethod->klass->name_space, "System") == 0) &&
5997                    (strcmp (cmethod->klass->name, "Environment") == 0)) {
5998                 if (!strcmp (cmethod->name, "get_IsRunningOnWindows") && fsig->param_count == 0) {
5999 #ifdef TARGET_WIN32
6000                         EMIT_NEW_ICONST (cfg, ins, 1);
6001 #else
6002                         EMIT_NEW_ICONST (cfg, ins, 0);
6003 #endif
6004                 }
6005         } else if (cmethod->klass->image == mono_defaults.corlib &&
6006                            (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
6007                            (strcmp (cmethod->klass->name, "Assembly") == 0)) {
6008                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetExecutingAssembly")) {
6009                         /* No stack walks are currently available, so implement this as an intrinsic */
6010                         MonoInst *assembly_ins;
6011
6012                         EMIT_NEW_AOTCONST (cfg, assembly_ins, MONO_PATCH_INFO_IMAGE, cfg->method->klass->image);
6013                         ins = mono_emit_jit_icall (cfg, mono_get_assembly_object, &assembly_ins);
6014                         return ins;
6015                 }
6016         } else if (cmethod->klass->image == mono_defaults.corlib &&
6017                            (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
6018                            (strcmp (cmethod->klass->name, "MethodBase") == 0)) {
6019                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetCurrentMethod")) {
6020                         /* No stack walks are currently available, so implement this as an intrinsic */
6021                         MonoInst *method_ins;
6022                         MonoMethod *declaring = cfg->method;
6023
6024                         /* This returns the declaring generic method */
6025                         if (declaring->is_inflated)
6026                                 declaring = ((MonoMethodInflated*)cfg->method)->declaring;
6027                         EMIT_NEW_AOTCONST (cfg, method_ins, MONO_PATCH_INFO_METHODCONST, declaring);
6028                         ins = mono_emit_jit_icall (cfg, mono_get_method_object, &method_ins);
6029                         cfg->no_inline = TRUE;
6030                         if (cfg->method != cfg->current_method)
6031                                 inline_failure (cfg, "MethodBase:GetCurrentMethod ()");
6032                         return ins;
6033                 }
6034         } else if (cmethod->klass == mono_defaults.math_class) {
6035                 /* 
6036                  * There is general branchless code for Min/Max, but it does not work for 
6037                  * all inputs:
6038                  * http://everything2.com/?node_id=1051618
6039                  */
6040         } else if (cmethod->klass == mono_defaults.systemtype_class && !strcmp (cmethod->name, "op_Equality")) {
6041                 EMIT_NEW_BIALU (cfg, ins, OP_COMPARE, -1, args [0]->dreg, args [1]->dreg);
6042                 MONO_INST_NEW (cfg, ins, OP_PCEQ);
6043                 ins->dreg = alloc_preg (cfg);
6044                 ins->type = STACK_I4;
6045                 MONO_ADD_INS (cfg->cbb, ins);
6046                 return ins;
6047         } else if (((!strcmp (cmethod->klass->image->assembly->aname.name, "MonoMac") ||
6048                     !strcmp (cmethod->klass->image->assembly->aname.name, "monotouch")) &&
6049                                 !strcmp (cmethod->klass->name_space, "XamCore.ObjCRuntime") &&
6050                                 !strcmp (cmethod->klass->name, "Selector")) ||
6051                            ((!strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.iOS") ||
6052                                  !strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.Mac")) &&
6053                                 !strcmp (cmethod->klass->name_space, "ObjCRuntime") &&
6054                                 !strcmp (cmethod->klass->name, "Selector"))
6055                            ) {
6056                 if ((cfg->backend->have_objc_get_selector || cfg->compile_llvm) &&
6057                         !strcmp (cmethod->name, "GetHandle") && fsig->param_count == 1 &&
6058                     (args [0]->opcode == OP_GOT_ENTRY || args [0]->opcode == OP_AOTCONST) &&
6059                     cfg->compile_aot) {
6060                         MonoInst *pi;
6061                         MonoJumpInfoToken *ji;
6062                         char *s;
6063
6064                         if (args [0]->opcode == OP_GOT_ENTRY) {
6065                                 pi = (MonoInst *)args [0]->inst_p1;
6066                                 g_assert (pi->opcode == OP_PATCH_INFO);
6067                                 g_assert (GPOINTER_TO_INT (pi->inst_p1) == MONO_PATCH_INFO_LDSTR);
6068                                 ji = (MonoJumpInfoToken *)pi->inst_p0;
6069                         } else {
6070                                 g_assert (GPOINTER_TO_INT (args [0]->inst_p1) == MONO_PATCH_INFO_LDSTR);
6071                                 ji = (MonoJumpInfoToken *)args [0]->inst_p0;
6072                         }
6073
6074                         NULLIFY_INS (args [0]);
6075
6076                         s = mono_ldstr_utf8 (ji->image, mono_metadata_token_index (ji->token), &cfg->error);
6077                         return_val_if_nok (&cfg->error, NULL);
6078
6079                         MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
6080                         ins->dreg = mono_alloc_ireg (cfg);
6081                         // FIXME: Leaks
6082                         ins->inst_p0 = s;
6083                         MONO_ADD_INS (cfg->cbb, ins);
6084                         return ins;
6085                 }
6086         }
6087
6088 #ifdef MONO_ARCH_SIMD_INTRINSICS
6089         if (cfg->opt & MONO_OPT_SIMD) {
6090                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
6091                 if (ins)
6092                         return ins;
6093         }
6094 #endif
6095
6096         ins = mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
6097         if (ins)
6098                 return ins;
6099
6100         if (COMPILE_LLVM (cfg)) {
6101                 ins = llvm_emit_inst_for_method (cfg, cmethod, fsig, args);
6102                 if (ins)
6103                         return ins;
6104         }
6105
6106         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
6107 }
6108
6109 /*
6110  * This entry point could be used later for arbitrary method
6111  * redirection.
6112  */
6113 inline static MonoInst*
6114 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
6115                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this_ins)
6116 {
6117         if (method->klass == mono_defaults.string_class) {
6118                 /* managed string allocation support */
6119                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
6120                         MonoInst *iargs [2];
6121                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
6122                         MonoMethod *managed_alloc = NULL;
6123
6124                         g_assert (vtable); /*Should not fail since it System.String*/
6125 #ifndef MONO_CROSS_COMPILE
6126                         managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE, FALSE);
6127 #endif
6128                         if (!managed_alloc)
6129                                 return NULL;
6130                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
6131                         iargs [1] = args [0];
6132                         return mono_emit_method_call (cfg, managed_alloc, iargs, this_ins);
6133                 }
6134         }
6135         return NULL;
6136 }
6137
6138 static void
6139 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
6140 {
6141         MonoInst *store, *temp;
6142         int i;
6143
6144         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
6145                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
6146
6147                 /*
6148                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
6149                  * would be different than the MonoInst's used to represent arguments, and
6150                  * the ldelema implementation can't deal with that.
6151                  * Solution: When ldelema is used on an inline argument, create a var for 
6152                  * it, emit ldelema on that var, and emit the saving code below in
6153                  * inline_method () if needed.
6154                  */
6155                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
6156                 cfg->args [i] = temp;
6157                 /* This uses cfg->args [i] which is set by the preceeding line */
6158                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
6159                 store->cil_code = sp [0]->cil_code;
6160                 sp++;
6161         }
6162 }
6163
6164 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
6165 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
6166
6167 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6168 static gboolean
6169 check_inline_called_method_name_limit (MonoMethod *called_method)
6170 {
6171         int strncmp_result;
6172         static const char *limit = NULL;
6173         
6174         if (limit == NULL) {
6175                 const char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
6176
6177                 if (limit_string != NULL)
6178                         limit = limit_string;
6179                 else
6180                         limit = "";
6181         }
6182
6183         if (limit [0] != '\0') {
6184                 char *called_method_name = mono_method_full_name (called_method, TRUE);
6185
6186                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
6187                 g_free (called_method_name);
6188         
6189                 //return (strncmp_result <= 0);
6190                 return (strncmp_result == 0);
6191         } else {
6192                 return TRUE;
6193         }
6194 }
6195 #endif
6196
6197 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6198 static gboolean
6199 check_inline_caller_method_name_limit (MonoMethod *caller_method)
6200 {
6201         int strncmp_result;
6202         static const char *limit = NULL;
6203         
6204         if (limit == NULL) {
6205                 const char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
6206                 if (limit_string != NULL) {
6207                         limit = limit_string;
6208                 } else {
6209                         limit = "";
6210                 }
6211         }
6212
6213         if (limit [0] != '\0') {
6214                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
6215
6216                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
6217                 g_free (caller_method_name);
6218         
6219                 //return (strncmp_result <= 0);
6220                 return (strncmp_result == 0);
6221         } else {
6222                 return TRUE;
6223         }
6224 }
6225 #endif
6226
6227 static void
6228 emit_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6229 {
6230         static double r8_0 = 0.0;
6231         static float r4_0 = 0.0;
6232         MonoInst *ins;
6233         int t;
6234
6235         rtype = mini_get_underlying_type (rtype);
6236         t = rtype->type;
6237
6238         if (rtype->byref) {
6239                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6240         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6241                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
6242         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6243                 MONO_EMIT_NEW_I8CONST (cfg, dreg, 0);
6244         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6245                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
6246                 ins->type = STACK_R4;
6247                 ins->inst_p0 = (void*)&r4_0;
6248                 ins->dreg = dreg;
6249                 MONO_ADD_INS (cfg->cbb, ins);
6250         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6251                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
6252                 ins->type = STACK_R8;
6253                 ins->inst_p0 = (void*)&r8_0;
6254                 ins->dreg = dreg;
6255                 MONO_ADD_INS (cfg->cbb, ins);
6256         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6257                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6258                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6259         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
6260                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6261         } else {
6262                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6263         }
6264 }
6265
6266 static void
6267 emit_dummy_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6268 {
6269         int t;
6270
6271         rtype = mini_get_underlying_type (rtype);
6272         t = rtype->type;
6273
6274         if (rtype->byref) {
6275                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_PCONST);
6276         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6277                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_ICONST);
6278         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6279                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_I8CONST);
6280         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6281                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R4CONST);
6282         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6283                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R8CONST);
6284         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6285                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6286                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6287         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
6288                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6289         } else {
6290                 emit_init_rvar (cfg, dreg, rtype);
6291         }
6292 }
6293
6294 /* If INIT is FALSE, emit dummy initialization statements to keep the IR valid */
6295 static void
6296 emit_init_local (MonoCompile *cfg, int local, MonoType *type, gboolean init)
6297 {
6298         MonoInst *var = cfg->locals [local];
6299         if (COMPILE_SOFT_FLOAT (cfg)) {
6300                 MonoInst *store;
6301                 int reg = alloc_dreg (cfg, (MonoStackType)var->type);
6302                 emit_init_rvar (cfg, reg, type);
6303                 EMIT_NEW_LOCSTORE (cfg, store, local, cfg->cbb->last_ins);
6304         } else {
6305                 if (init)
6306                         emit_init_rvar (cfg, var->dreg, type);
6307                 else
6308                         emit_dummy_init_rvar (cfg, var->dreg, type);
6309         }
6310 }
6311
6312 int
6313 mini_inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp, guchar *ip, guint real_offset, gboolean inline_always)
6314 {
6315         return inline_method (cfg, cmethod, fsig, sp, ip, real_offset, inline_always);
6316 }
6317
6318 /*
6319  * inline_method:
6320  *
6321  * Return the cost of inlining CMETHOD, or zero if it should not be inlined.
6322  */
6323 static int
6324 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
6325                guchar *ip, guint real_offset, gboolean inline_always)
6326 {
6327         MonoError error;
6328         MonoInst *ins, *rvar = NULL;
6329         MonoMethodHeader *cheader;
6330         MonoBasicBlock *ebblock, *sbblock;
6331         int i, costs;
6332         MonoMethod *prev_inlined_method;
6333         MonoInst **prev_locals, **prev_args;
6334         MonoType **prev_arg_types;
6335         guint prev_real_offset;
6336         GHashTable *prev_cbb_hash;
6337         MonoBasicBlock **prev_cil_offset_to_bb;
6338         MonoBasicBlock *prev_cbb;
6339         const unsigned char *prev_ip;
6340         unsigned char *prev_cil_start;
6341         guint32 prev_cil_offset_to_bb_len;
6342         MonoMethod *prev_current_method;
6343         MonoGenericContext *prev_generic_context;
6344         gboolean ret_var_set, prev_ret_var_set, prev_disable_inline, virtual_ = FALSE;
6345
6346         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
6347
6348 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6349         if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
6350                 return 0;
6351 #endif
6352 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6353         if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
6354                 return 0;
6355 #endif
6356
6357         if (!fsig)
6358                 fsig = mono_method_signature (cmethod);
6359
6360         if (cfg->verbose_level > 2)
6361                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6362
6363         if (!cmethod->inline_info) {
6364                 cfg->stat_inlineable_methods++;
6365                 cmethod->inline_info = 1;
6366         }
6367
6368         /* allocate local variables */
6369         cheader = mono_method_get_header_checked (cmethod, &error);
6370         if (!cheader) {
6371                 if (inline_always) {
6372                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
6373                         mono_error_move (&cfg->error, &error);
6374                 } else {
6375                         mono_error_cleanup (&error);
6376                 }
6377                 return 0;
6378         }
6379
6380         /*Must verify before creating locals as it can cause the JIT to assert.*/
6381         if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
6382                 mono_metadata_free_mh (cheader);
6383                 return 0;
6384         }
6385
6386         /* allocate space to store the return value */
6387         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
6388                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
6389         }
6390
6391         prev_locals = cfg->locals;
6392         cfg->locals = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));
6393         for (i = 0; i < cheader->num_locals; ++i)
6394                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
6395
6396         /* allocate start and end blocks */
6397         /* This is needed so if the inline is aborted, we can clean up */
6398         NEW_BBLOCK (cfg, sbblock);
6399         sbblock->real_offset = real_offset;
6400
6401         NEW_BBLOCK (cfg, ebblock);
6402         ebblock->block_num = cfg->num_bblocks++;
6403         ebblock->real_offset = real_offset;
6404
6405         prev_args = cfg->args;
6406         prev_arg_types = cfg->arg_types;
6407         prev_inlined_method = cfg->inlined_method;
6408         cfg->inlined_method = cmethod;
6409         cfg->ret_var_set = FALSE;
6410         cfg->inline_depth ++;
6411         prev_real_offset = cfg->real_offset;
6412         prev_cbb_hash = cfg->cbb_hash;
6413         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
6414         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
6415         prev_cil_start = cfg->cil_start;
6416         prev_ip = cfg->ip;
6417         prev_cbb = cfg->cbb;
6418         prev_current_method = cfg->current_method;
6419         prev_generic_context = cfg->generic_context;
6420         prev_ret_var_set = cfg->ret_var_set;
6421         prev_disable_inline = cfg->disable_inline;
6422
6423         if (ip && *ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
6424                 virtual_ = TRUE;
6425
6426         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, sp, real_offset, virtual_);
6427
6428         ret_var_set = cfg->ret_var_set;
6429
6430         cfg->inlined_method = prev_inlined_method;
6431         cfg->real_offset = prev_real_offset;
6432         cfg->cbb_hash = prev_cbb_hash;
6433         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
6434         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
6435         cfg->cil_start = prev_cil_start;
6436         cfg->ip = prev_ip;
6437         cfg->locals = prev_locals;
6438         cfg->args = prev_args;
6439         cfg->arg_types = prev_arg_types;
6440         cfg->current_method = prev_current_method;
6441         cfg->generic_context = prev_generic_context;
6442         cfg->ret_var_set = prev_ret_var_set;
6443         cfg->disable_inline = prev_disable_inline;
6444         cfg->inline_depth --;
6445
6446         if ((costs >= 0 && costs < 60) || inline_always || (costs >= 0 && (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))) {
6447                 if (cfg->verbose_level > 2)
6448                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6449                 
6450                 cfg->stat_inlined_methods++;
6451
6452                 /* always add some code to avoid block split failures */
6453                 MONO_INST_NEW (cfg, ins, OP_NOP);
6454                 MONO_ADD_INS (prev_cbb, ins);
6455
6456                 prev_cbb->next_bb = sbblock;
6457                 link_bblock (cfg, prev_cbb, sbblock);
6458
6459                 /* 
6460                  * Get rid of the begin and end bblocks if possible to aid local
6461                  * optimizations.
6462                  */
6463                 mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
6464
6465                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
6466                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
6467
6468                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
6469                         MonoBasicBlock *prev = ebblock->in_bb [0];
6470
6471                         if (prev->next_bb == ebblock) {
6472                                 mono_merge_basic_blocks (cfg, prev, ebblock);
6473                                 cfg->cbb = prev;
6474                                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
6475                                         mono_merge_basic_blocks (cfg, prev_cbb, prev);
6476                                         cfg->cbb = prev_cbb;
6477                                 }
6478                         } else {
6479                                 /* There could be a bblock after 'prev', and making 'prev' the current bb could cause problems */
6480                                 cfg->cbb = ebblock;
6481                         }
6482                 } else {
6483                         /* 
6484                          * Its possible that the rvar is set in some prev bblock, but not in others.
6485                          * (#1835).
6486                          */
6487                         if (rvar) {
6488                                 MonoBasicBlock *bb;
6489
6490                                 for (i = 0; i < ebblock->in_count; ++i) {
6491                                         bb = ebblock->in_bb [i];
6492
6493                                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
6494                                                 cfg->cbb = bb;
6495
6496                                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
6497                                         }
6498                                 }
6499                         }
6500
6501                         cfg->cbb = ebblock;
6502                 }
6503
6504                 if (rvar) {
6505                         /*
6506                          * If the inlined method contains only a throw, then the ret var is not 
6507                          * set, so set it to a dummy value.
6508                          */
6509                         if (!ret_var_set)
6510                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
6511
6512                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
6513                         *sp++ = ins;
6514                 }
6515                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
6516                 return costs + 1;
6517         } else {
6518                 if (cfg->verbose_level > 2)
6519                         printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
6520                 cfg->exception_type = MONO_EXCEPTION_NONE;
6521
6522                 /* This gets rid of the newly added bblocks */
6523                 cfg->cbb = prev_cbb;
6524         }
6525         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
6526         return 0;
6527 }
6528
6529 /*
6530  * Some of these comments may well be out-of-date.
6531  * Design decisions: we do a single pass over the IL code (and we do bblock 
6532  * splitting/merging in the few cases when it's required: a back jump to an IL
6533  * address that was not already seen as bblock starting point).
6534  * Code is validated as we go (full verification is still better left to metadata/verify.c).
6535  * Complex operations are decomposed in simpler ones right away. We need to let the 
6536  * arch-specific code peek and poke inside this process somehow (except when the 
6537  * optimizations can take advantage of the full semantic info of coarse opcodes).
6538  * All the opcodes of the form opcode.s are 'normalized' to opcode.
6539  * MonoInst->opcode initially is the IL opcode or some simplification of that 
6540  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
6541  * opcode with value bigger than OP_LAST.
6542  * At this point the IR can be handed over to an interpreter, a dumb code generator
6543  * or to the optimizing code generator that will translate it to SSA form.
6544  *
6545  * Profiling directed optimizations.
6546  * We may compile by default with few or no optimizations and instrument the code
6547  * or the user may indicate what methods to optimize the most either in a config file
6548  * or through repeated runs where the compiler applies offline the optimizations to 
6549  * each method and then decides if it was worth it.
6550  */
6551
6552 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
6553 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
6554 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
6555 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
6556 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
6557 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
6558 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
6559 #define CHECK_TYPELOAD(klass) if (!(klass) || mono_class_has_failure (klass)) TYPE_LOAD_ERROR ((klass))
6560
6561 /* offset from br.s -> br like opcodes */
6562 #define BIG_BRANCH_OFFSET 13
6563
6564 static gboolean
6565 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
6566 {
6567         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
6568
6569         return b == NULL || b == bb;
6570 }
6571
6572 static int
6573 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
6574 {
6575         unsigned char *ip = start;
6576         unsigned char *target;
6577         int i;
6578         guint cli_addr;
6579         MonoBasicBlock *bblock;
6580         const MonoOpcode *opcode;
6581
6582         while (ip < end) {
6583                 cli_addr = ip - start;
6584                 i = mono_opcode_value ((const guint8 **)&ip, end);
6585                 if (i < 0)
6586                         UNVERIFIED;
6587                 opcode = &mono_opcodes [i];
6588                 switch (opcode->argument) {
6589                 case MonoInlineNone:
6590                         ip++; 
6591                         break;
6592                 case MonoInlineString:
6593                 case MonoInlineType:
6594                 case MonoInlineField:
6595                 case MonoInlineMethod:
6596                 case MonoInlineTok:
6597                 case MonoInlineSig:
6598                 case MonoShortInlineR:
6599                 case MonoInlineI:
6600                         ip += 5;
6601                         break;
6602                 case MonoInlineVar:
6603                         ip += 3;
6604                         break;
6605                 case MonoShortInlineVar:
6606                 case MonoShortInlineI:
6607                         ip += 2;
6608                         break;
6609                 case MonoShortInlineBrTarget:
6610                         target = start + cli_addr + 2 + (signed char)ip [1];
6611                         GET_BBLOCK (cfg, bblock, target);
6612                         ip += 2;
6613                         if (ip < end)
6614                                 GET_BBLOCK (cfg, bblock, ip);
6615                         break;
6616                 case MonoInlineBrTarget:
6617                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
6618                         GET_BBLOCK (cfg, bblock, target);
6619                         ip += 5;
6620                         if (ip < end)
6621                                 GET_BBLOCK (cfg, bblock, ip);
6622                         break;
6623                 case MonoInlineSwitch: {
6624                         guint32 n = read32 (ip + 1);
6625                         guint32 j;
6626                         ip += 5;
6627                         cli_addr += 5 + 4 * n;
6628                         target = start + cli_addr;
6629                         GET_BBLOCK (cfg, bblock, target);
6630                         
6631                         for (j = 0; j < n; ++j) {
6632                                 target = start + cli_addr + (gint32)read32 (ip);
6633                                 GET_BBLOCK (cfg, bblock, target);
6634                                 ip += 4;
6635                         }
6636                         break;
6637                 }
6638                 case MonoInlineR:
6639                 case MonoInlineI8:
6640                         ip += 9;
6641                         break;
6642                 default:
6643                         g_assert_not_reached ();
6644                 }
6645
6646                 if (i == CEE_THROW) {
6647                         unsigned char *bb_start = ip - 1;
6648                         
6649                         /* Find the start of the bblock containing the throw */
6650                         bblock = NULL;
6651                         while ((bb_start >= start) && !bblock) {
6652                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
6653                                 bb_start --;
6654                         }
6655                         if (bblock)
6656                                 bblock->out_of_line = 1;
6657                 }
6658         }
6659         return 0;
6660 unverified:
6661 exception_exit:
6662         *pos = ip;
6663         return 1;
6664 }
6665
6666 static inline MonoMethod *
6667 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context, MonoError *error)
6668 {
6669         MonoMethod *method;
6670
6671         mono_error_init (error);
6672
6673         if (m->wrapper_type != MONO_WRAPPER_NONE) {
6674                 method = (MonoMethod *)mono_method_get_wrapper_data (m, token);
6675                 if (context) {
6676                         method = mono_class_inflate_generic_method_checked (method, context, error);
6677                 }
6678         } else {
6679                 method = mono_get_method_checked (m->klass->image, token, klass, context, error);
6680         }
6681
6682         return method;
6683 }
6684
6685 static inline MonoMethod *
6686 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
6687 {
6688         MonoError error;
6689         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context, cfg ? &cfg->error : &error);
6690
6691         if (method && cfg && !cfg->gshared && mono_class_is_open_constructed_type (&method->klass->byval_arg)) {
6692                 mono_error_set_bad_image (&cfg->error, cfg->method->klass->image, "Method with open type while not compiling gshared");
6693                 method = NULL;
6694         }
6695
6696         if (!method && !cfg)
6697                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
6698
6699         return method;
6700 }
6701
6702 static inline MonoClass*
6703 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
6704 {
6705         MonoError error;
6706         MonoClass *klass;
6707
6708         if (method->wrapper_type != MONO_WRAPPER_NONE) {
6709                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
6710                 if (context) {
6711                         klass = mono_class_inflate_generic_class_checked (klass, context, &error);
6712                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
6713                 }
6714         } else {
6715                 klass = mono_class_get_and_inflate_typespec_checked (method->klass->image, token, context, &error);
6716                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
6717         }
6718         if (klass)
6719                 mono_class_init (klass);
6720         return klass;
6721 }
6722
6723 static inline MonoMethodSignature*
6724 mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context, MonoError *error)
6725 {
6726         MonoMethodSignature *fsig;
6727
6728         mono_error_init (error);
6729         if (method->wrapper_type != MONO_WRAPPER_NONE) {
6730                 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
6731         } else {
6732                 fsig = mono_metadata_parse_signature_checked (method->klass->image, token, error);
6733                 return_val_if_nok (error, NULL);
6734         }
6735         if (context) {
6736                 fsig = mono_inflate_generic_signature(fsig, context, error);
6737         }
6738         return fsig;
6739 }
6740
6741 static MonoMethod*
6742 throw_exception (void)
6743 {
6744         static MonoMethod *method = NULL;
6745
6746         if (!method) {
6747                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
6748                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
6749         }
6750         g_assert (method);
6751         return method;
6752 }
6753
6754 static void
6755 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
6756 {
6757         MonoMethod *thrower = throw_exception ();
6758         MonoInst *args [1];
6759
6760         EMIT_NEW_PCONST (cfg, args [0], ex);
6761         mono_emit_method_call (cfg, thrower, args, NULL);
6762 }
6763
6764 /*
6765  * Return the original method is a wrapper is specified. We can only access 
6766  * the custom attributes from the original method.
6767  */
6768 static MonoMethod*
6769 get_original_method (MonoMethod *method)
6770 {
6771         if (method->wrapper_type == MONO_WRAPPER_NONE)
6772                 return method;
6773
6774         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
6775         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
6776                 return NULL;
6777
6778         /* in other cases we need to find the original method */
6779         return mono_marshal_method_from_wrapper (method);
6780 }
6781
6782 static void
6783 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field)
6784 {
6785         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
6786         MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
6787         if (ex)
6788                 emit_throw_exception (cfg, ex);
6789 }
6790
6791 static void
6792 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
6793 {
6794         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
6795         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
6796         if (ex)
6797                 emit_throw_exception (cfg, ex);
6798 }
6799
6800 /*
6801  * Check that the IL instructions at ip are the array initialization
6802  * sequence and return the pointer to the data and the size.
6803  */
6804 static const char*
6805 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
6806 {
6807         /*
6808          * newarr[System.Int32]
6809          * dup
6810          * ldtoken field valuetype ...
6811          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
6812          */
6813         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
6814                 MonoError error;
6815                 guint32 token = read32 (ip + 7);
6816                 guint32 field_token = read32 (ip + 2);
6817                 guint32 field_index = field_token & 0xffffff;
6818                 guint32 rva;
6819                 const char *data_ptr;
6820                 int size = 0;
6821                 MonoMethod *cmethod;
6822                 MonoClass *dummy_class;
6823                 MonoClassField *field = mono_field_from_token_checked (method->klass->image, field_token, &dummy_class, NULL, &error);
6824                 int dummy_align;
6825
6826                 if (!field) {
6827                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
6828                         return NULL;
6829                 }
6830
6831                 *out_field_token = field_token;
6832
6833                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
6834                 if (!cmethod)
6835                         return NULL;
6836                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
6837                         return NULL;
6838                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
6839                 case MONO_TYPE_BOOLEAN:
6840                 case MONO_TYPE_I1:
6841                 case MONO_TYPE_U1:
6842                         size = 1; break;
6843                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
6844 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
6845                 case MONO_TYPE_CHAR:
6846                 case MONO_TYPE_I2:
6847                 case MONO_TYPE_U2:
6848                         size = 2; break;
6849                 case MONO_TYPE_I4:
6850                 case MONO_TYPE_U4:
6851                 case MONO_TYPE_R4:
6852                         size = 4; break;
6853                 case MONO_TYPE_R8:
6854                 case MONO_TYPE_I8:
6855                 case MONO_TYPE_U8:
6856                         size = 8; break;
6857 #endif
6858                 default:
6859                         return NULL;
6860                 }
6861                 size *= len;
6862                 if (size > mono_type_size (field->type, &dummy_align))
6863                     return NULL;
6864                 *out_size = size;
6865                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
6866                 if (!image_is_dynamic (method->klass->image)) {
6867                         field_index = read32 (ip + 2) & 0xffffff;
6868                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
6869                         data_ptr = mono_image_rva_map (method->klass->image, rva);
6870                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
6871                         /* for aot code we do the lookup on load */
6872                         if (aot && data_ptr)
6873                                 return (const char *)GUINT_TO_POINTER (rva);
6874                 } else {
6875                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
6876                         g_assert (!aot);
6877                         data_ptr = mono_field_get_data (field);
6878                 }
6879                 return data_ptr;
6880         }
6881         return NULL;
6882 }
6883
6884 static void
6885 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
6886 {
6887         MonoError error;
6888         char *method_fname = mono_method_full_name (method, TRUE);
6889         char *method_code;
6890         MonoMethodHeader *header = mono_method_get_header_checked (method, &error);
6891
6892         if (!header) {
6893                 method_code = g_strdup_printf ("could not parse method body due to %s", mono_error_get_message (&error));
6894                 mono_error_cleanup (&error);
6895         } else if (header->code_size == 0)
6896                 method_code = g_strdup ("method body is empty.");
6897         else
6898                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
6899         mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code));
6900         g_free (method_fname);
6901         g_free (method_code);
6902         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
6903 }
6904
6905 static void
6906 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
6907 {
6908         MonoInst *ins;
6909         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
6910         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
6911                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
6912                 /* Optimize reg-reg moves away */
6913                 /* 
6914                  * Can't optimize other opcodes, since sp[0] might point to
6915                  * the last ins of a decomposed opcode.
6916                  */
6917                 sp [0]->dreg = (cfg)->locals [n]->dreg;
6918         } else {
6919                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
6920         }
6921 }
6922
6923 /*
6924  * ldloca inhibits many optimizations so try to get rid of it in common
6925  * cases.
6926  */
6927 static inline unsigned char *
6928 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
6929 {
6930         int local, token;
6931         MonoClass *klass;
6932         MonoType *type;
6933
6934         if (size == 1) {
6935                 local = ip [1];
6936                 ip += 2;
6937         } else {
6938                 local = read16 (ip + 2);
6939                 ip += 4;
6940         }
6941         
6942         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
6943                 /* From the INITOBJ case */
6944                 token = read32 (ip + 2);
6945                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
6946                 CHECK_TYPELOAD (klass);
6947                 type = mini_get_underlying_type (&klass->byval_arg);
6948                 emit_init_local (cfg, local, type, TRUE);
6949                 return ip + 6;
6950         }
6951  exception_exit:
6952         return NULL;
6953 }
6954
6955 static MonoInst*
6956 emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used, MonoInst **sp)
6957 {
6958         MonoInst *icall_args [16];
6959         MonoInst *call_target, *ins, *vtable_ins;
6960         int arg_reg, this_reg, vtable_reg;
6961         gboolean is_iface = mono_class_is_interface (cmethod->klass);
6962         gboolean is_gsharedvt = cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig);
6963         gboolean variant_iface = FALSE;
6964         guint32 slot;
6965         int offset;
6966
6967         /*
6968          * In llvm-only mode, vtables contain function descriptors instead of
6969          * method addresses/trampolines.
6970          */
6971         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
6972
6973         if (is_iface)
6974                 slot = mono_method_get_imt_slot (cmethod);
6975         else
6976                 slot = mono_method_get_vtable_index (cmethod);
6977
6978         this_reg = sp [0]->dreg;
6979
6980         if (is_iface && mono_class_has_variant_generic_params (cmethod->klass))
6981                 variant_iface = TRUE;
6982
6983         if (!fsig->generic_param_count && !is_iface && !is_gsharedvt) {
6984                 /*
6985                  * The simplest case, a normal virtual call.
6986                  */
6987                 int slot_reg = alloc_preg (cfg);
6988                 int addr_reg = alloc_preg (cfg);
6989                 int arg_reg = alloc_preg (cfg);
6990                 MonoBasicBlock *non_null_bb;
6991
6992                 vtable_reg = alloc_preg (cfg);
6993                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
6994                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + (slot * SIZEOF_VOID_P);
6995
6996                 /* Load the vtable slot, which contains a function descriptor. */
6997                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
6998
6999                 NEW_BBLOCK (cfg, non_null_bb);
7000
7001                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, slot_reg, 0);
7002                 cfg->cbb->last_ins->flags |= MONO_INST_LIKELY;
7003                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, non_null_bb);
7004
7005                 /* Slow path */
7006                 // FIXME: Make the wrapper use the preserveall cconv
7007                 // FIXME: Use one icall per slot for small slot numbers ?
7008                 icall_args [0] = vtable_ins;
7009                 EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7010                 /* Make the icall return the vtable slot value to save some code space */
7011                 ins = mono_emit_jit_icall (cfg, mono_init_vtable_slot, icall_args);
7012                 ins->dreg = slot_reg;
7013                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, non_null_bb);
7014
7015                 /* Fastpath */
7016                 MONO_START_BB (cfg, non_null_bb);
7017                 /* Load the address + arg from the vtable slot */
7018                 EMIT_NEW_LOAD_MEMBASE (cfg, call_target, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7019                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, arg_reg, slot_reg, SIZEOF_VOID_P);
7020
7021                 return emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
7022         }
7023
7024         if (!fsig->generic_param_count && is_iface && !variant_iface && !is_gsharedvt) {
7025                 /*
7026                  * A simple interface call
7027                  *
7028                  * We make a call through an imt slot to obtain the function descriptor we need to call.
7029                  * The imt slot contains a function descriptor for a runtime function + arg.
7030                  */
7031                 int slot_reg = alloc_preg (cfg);
7032                 int addr_reg = alloc_preg (cfg);
7033                 int arg_reg = alloc_preg (cfg);
7034                 MonoInst *thunk_addr_ins, *thunk_arg_ins, *ftndesc_ins;
7035
7036                 vtable_reg = alloc_preg (cfg);
7037                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7038                 offset = ((gint32)slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
7039
7040                 /*
7041                  * The slot is already initialized when the vtable is created so there is no need
7042                  * to check it here.
7043                  */
7044
7045                 /* Load the imt slot, which contains a function descriptor. */
7046                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7047
7048                 /* Load the address + arg of the imt thunk from the imt slot */
7049                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_addr_ins, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7050                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_arg_ins, OP_LOAD_MEMBASE, arg_reg, slot_reg, SIZEOF_VOID_P);
7051                 /*
7052                  * IMT thunks in llvm-only mode are C functions which take an info argument
7053                  * plus the imt method and return the ftndesc to call.
7054                  */
7055                 icall_args [0] = thunk_arg_ins;
7056                 icall_args [1] = emit_get_rgctx_method (cfg, context_used,
7057                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7058                 ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_trampoline, icall_args, thunk_addr_ins, NULL, NULL);
7059
7060                 return emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
7061         }
7062
7063         if ((fsig->generic_param_count || variant_iface) && !is_gsharedvt) {
7064                 /*
7065                  * This is similar to the interface case, the vtable slot points to an imt thunk which is
7066                  * dynamically extended as more instantiations are discovered.
7067                  * This handles generic virtual methods both on classes and interfaces.
7068                  */
7069                 int slot_reg = alloc_preg (cfg);
7070                 int addr_reg = alloc_preg (cfg);
7071                 int arg_reg = alloc_preg (cfg);
7072                 int ftndesc_reg = alloc_preg (cfg);
7073                 MonoInst *thunk_addr_ins, *thunk_arg_ins, *ftndesc_ins;
7074                 MonoBasicBlock *slowpath_bb, *end_bb;
7075
7076                 NEW_BBLOCK (cfg, slowpath_bb);
7077                 NEW_BBLOCK (cfg, end_bb);
7078
7079                 vtable_reg = alloc_preg (cfg);
7080                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7081                 if (is_iface)
7082                         offset = ((gint32)slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
7083                 else
7084                         offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + (slot * SIZEOF_VOID_P);
7085
7086                 /* Load the slot, which contains a function descriptor. */
7087                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7088
7089                 /* These slots are not initialized, so fall back to the slow path until they are initialized */
7090                 /* That happens when mono_method_add_generic_virtual_invocation () creates an IMT thunk */
7091                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, slot_reg, 0);
7092                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, slowpath_bb);
7093
7094                 /* Fastpath */
7095                 /* Same as with iface calls */
7096                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_addr_ins, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7097                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_arg_ins, OP_LOAD_MEMBASE, arg_reg, slot_reg, SIZEOF_VOID_P);
7098                 icall_args [0] = thunk_arg_ins;
7099                 icall_args [1] = emit_get_rgctx_method (cfg, context_used,
7100                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7101                 ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_trampoline, icall_args, thunk_addr_ins, NULL, NULL);
7102                 ftndesc_ins->dreg = ftndesc_reg;
7103                 /*
7104                  * Unlike normal iface calls, these imt thunks can return NULL, i.e. when they are passed an instantiation
7105                  * they don't know about yet. Fall back to the slowpath in that case.
7106                  */
7107                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ftndesc_reg, 0);
7108                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, slowpath_bb);
7109
7110                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
7111
7112                 /* Slowpath */
7113                 MONO_START_BB (cfg, slowpath_bb);
7114                 icall_args [0] = vtable_ins;
7115                 EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7116                 icall_args [2] = emit_get_rgctx_method (cfg, context_used,
7117                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7118                 if (is_iface)
7119                         ftndesc_ins = mono_emit_jit_icall (cfg, mono_resolve_generic_virtual_iface_call, icall_args);
7120                 else
7121                         ftndesc_ins = mono_emit_jit_icall (cfg, mono_resolve_generic_virtual_call, icall_args);
7122                 ftndesc_ins->dreg = ftndesc_reg;
7123                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
7124
7125                 /* Common case */
7126                 MONO_START_BB (cfg, end_bb);
7127                 return emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
7128         }
7129
7130         /*
7131          * Non-optimized cases
7132          */
7133         icall_args [0] = sp [0];
7134         EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7135
7136         icall_args [2] = emit_get_rgctx_method (cfg, context_used,
7137                                                                                         cmethod, MONO_RGCTX_INFO_METHOD);
7138
7139         arg_reg = alloc_preg (cfg);
7140         MONO_EMIT_NEW_PCONST (cfg, arg_reg, NULL);
7141         EMIT_NEW_VARLOADA_VREG (cfg, icall_args [3], arg_reg, &mono_defaults.int_class->byval_arg);
7142
7143         g_assert (is_gsharedvt);
7144         if (is_iface)
7145                 call_target = mono_emit_jit_icall (cfg, mono_resolve_iface_call_gsharedvt, icall_args);
7146         else
7147                 call_target = mono_emit_jit_icall (cfg, mono_resolve_vcall_gsharedvt, icall_args);
7148
7149         /*
7150          * Pass the extra argument even if the callee doesn't receive it, most
7151          * calling conventions allow this.
7152          */
7153         return emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
7154 }
7155
7156 static gboolean
7157 is_exception_class (MonoClass *klass)
7158 {
7159         while (klass) {
7160                 if (klass == mono_defaults.exception_class)
7161                         return TRUE;
7162                 klass = klass->parent;
7163         }
7164         return FALSE;
7165 }
7166
7167 /*
7168  * is_jit_optimizer_disabled:
7169  *
7170  *   Determine whenever M's assembly has a DebuggableAttribute with the
7171  * IsJITOptimizerDisabled flag set.
7172  */
7173 static gboolean
7174 is_jit_optimizer_disabled (MonoMethod *m)
7175 {
7176         MonoError error;
7177         MonoAssembly *ass = m->klass->image->assembly;
7178         MonoCustomAttrInfo* attrs;
7179         MonoClass *klass;
7180         int i;
7181         gboolean val = FALSE;
7182
7183         g_assert (ass);
7184         if (ass->jit_optimizer_disabled_inited)
7185                 return ass->jit_optimizer_disabled;
7186
7187         klass = mono_class_try_get_debuggable_attribute_class ();
7188
7189         if (!klass) {
7190                 /* Linked away */
7191                 ass->jit_optimizer_disabled = FALSE;
7192                 mono_memory_barrier ();
7193                 ass->jit_optimizer_disabled_inited = TRUE;
7194                 return FALSE;
7195         }
7196
7197         attrs = mono_custom_attrs_from_assembly_checked (ass, FALSE, &error);
7198         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7199         if (attrs) {
7200                 for (i = 0; i < attrs->num_attrs; ++i) {
7201                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
7202                         const gchar *p;
7203                         MonoMethodSignature *sig;
7204
7205                         if (!attr->ctor || attr->ctor->klass != klass)
7206                                 continue;
7207                         /* Decode the attribute. See reflection.c */
7208                         p = (const char*)attr->data;
7209                         g_assert (read16 (p) == 0x0001);
7210                         p += 2;
7211
7212                         // FIXME: Support named parameters
7213                         sig = mono_method_signature (attr->ctor);
7214                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
7215                                 continue;
7216                         /* Two boolean arguments */
7217                         p ++;
7218                         val = *p;
7219                 }
7220                 mono_custom_attrs_free (attrs);
7221         }
7222
7223         ass->jit_optimizer_disabled = val;
7224         mono_memory_barrier ();
7225         ass->jit_optimizer_disabled_inited = TRUE;
7226
7227         return val;
7228 }
7229
7230 static gboolean
7231 is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig, int call_opcode)
7232 {
7233         gboolean supported_tail_call;
7234         int i;
7235
7236         supported_tail_call = mono_arch_tail_call_supported (cfg, mono_method_signature (method), mono_method_signature (cmethod));
7237
7238         for (i = 0; i < fsig->param_count; ++i) {
7239                 if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
7240                         /* These can point to the current method's stack */
7241                         supported_tail_call = FALSE;
7242         }
7243         if (fsig->hasthis && cmethod->klass->valuetype)
7244                 /* this might point to the current method's stack */
7245                 supported_tail_call = FALSE;
7246         if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
7247                 supported_tail_call = FALSE;
7248         if (cfg->method->save_lmf)
7249                 supported_tail_call = FALSE;
7250         if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
7251                 supported_tail_call = FALSE;
7252         if (call_opcode != CEE_CALL)
7253                 supported_tail_call = FALSE;
7254
7255         /* Debugging support */
7256 #if 0
7257         if (supported_tail_call) {
7258                 if (!mono_debug_count ())
7259                         supported_tail_call = FALSE;
7260         }
7261 #endif
7262
7263         return supported_tail_call;
7264 }
7265
7266 /*
7267  * handle_ctor_call:
7268  *
7269  *   Handle calls made to ctors from NEWOBJ opcodes.
7270  */
7271 static void
7272 handle_ctor_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used,
7273                                   MonoInst **sp, guint8 *ip, int *inline_costs)
7274 {
7275         MonoInst *vtable_arg = NULL, *callvirt_this_arg = NULL, *ins;
7276
7277         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
7278                                         mono_method_is_generic_sharable (cmethod, TRUE)) {
7279                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
7280                         mono_class_vtable (cfg->domain, cmethod->klass);
7281                         CHECK_TYPELOAD (cmethod->klass);
7282
7283                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
7284                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
7285                 } else {
7286                         if (context_used) {
7287                                 vtable_arg = mini_emit_get_rgctx_klass (cfg, context_used,
7288                                                                                                    cmethod->klass, MONO_RGCTX_INFO_VTABLE);
7289                         } else {
7290                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
7291
7292                                 CHECK_TYPELOAD (cmethod->klass);
7293                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
7294                         }
7295                 }
7296         }
7297
7298         /* Avoid virtual calls to ctors if possible */
7299         if (mono_class_is_marshalbyref (cmethod->klass))
7300                 callvirt_this_arg = sp [0];
7301
7302         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
7303                 g_assert (MONO_TYPE_IS_VOID (fsig->ret));
7304                 CHECK_CFG_EXCEPTION;
7305         } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
7306                            mono_method_check_inlining (cfg, cmethod) &&
7307                            !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE)) {
7308                 int costs;
7309
7310                 if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, FALSE))) {
7311                         cfg->real_offset += 5;
7312
7313                         *inline_costs += costs - 5;
7314                 } else {
7315                         INLINE_FAILURE ("inline failure");
7316                         // FIXME-VT: Clean this up
7317                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
7318                                 GSHAREDVT_FAILURE(*ip);
7319                         mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
7320                 }
7321         } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
7322                 MonoInst *addr;
7323
7324                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
7325
7326                 if (cfg->llvm_only) {
7327                         // FIXME: Avoid initializing vtable_arg
7328                         emit_llvmonly_calli (cfg, fsig, sp, addr);
7329                 } else {
7330                         mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
7331                 }
7332         } else if (context_used &&
7333                            ((!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
7334                                  !mono_class_generic_sharing_enabled (cmethod->klass)) || cfg->gsharedvt)) {
7335                 MonoInst *cmethod_addr;
7336
7337                 /* Generic calls made out of gsharedvt methods cannot be patched, so use an indirect call */
7338
7339                 if (cfg->llvm_only) {
7340                         MonoInst *addr = emit_get_rgctx_method (cfg, context_used, cmethod,
7341                                                                                                         MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
7342                         emit_llvmonly_calli (cfg, fsig, sp, addr);
7343                 } else {
7344                         cmethod_addr = emit_get_rgctx_method (cfg, context_used,
7345                                                                                                   cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
7346
7347                         mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
7348                 }
7349         } else {
7350                 INLINE_FAILURE ("ctor call");
7351                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
7352                                                                                   callvirt_this_arg, NULL, vtable_arg);
7353         }
7354  exception_exit:
7355         return;
7356 }
7357
7358 static void
7359 emit_setret (MonoCompile *cfg, MonoInst *val)
7360 {
7361         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (cfg->method)->ret);
7362         MonoInst *ins;
7363
7364         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
7365                 MonoInst *ret_addr;
7366
7367                 if (!cfg->vret_addr) {
7368                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, val);
7369                 } else {
7370                         EMIT_NEW_RETLOADA (cfg, ret_addr);
7371
7372                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, val->dreg);
7373                         ins->klass = mono_class_from_mono_type (ret_type);
7374                 }
7375         } else {
7376 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
7377                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
7378                         MonoInst *iargs [1];
7379                         MonoInst *conv;
7380
7381                         iargs [0] = val;
7382                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
7383                         mono_arch_emit_setret (cfg, cfg->method, conv);
7384                 } else {
7385                         mono_arch_emit_setret (cfg, cfg->method, val);
7386                 }
7387 #else
7388                 mono_arch_emit_setret (cfg, cfg->method, val);
7389 #endif
7390         }
7391 }
7392
7393 /*
7394  * mono_method_to_ir:
7395  *
7396  * Translate the .net IL into linear IR.
7397  *
7398  * @start_bblock: if not NULL, the starting basic block, used during inlining.
7399  * @end_bblock: if not NULL, the ending basic block, used during inlining.
7400  * @return_var: if not NULL, the place where the return value is stored, used during inlining.   
7401  * @inline_args: if not NULL, contains the arguments to the inline call
7402  * @inline_offset: if not zero, the real offset from the inline call, or zero otherwise.
7403  * @is_virtual_call: whether this method is being called as a result of a call to callvirt
7404  *
7405  * This method is used to turn ECMA IL into Mono's internal Linear IR
7406  * reprensetation.  It is used both for entire methods, as well as
7407  * inlining existing methods.  In the former case, the @start_bblock,
7408  * @end_bblock, @return_var, @inline_args are all set to NULL, and the
7409  * inline_offset is set to zero.
7410  * 
7411  * Returns: the inline cost, or -1 if there was an error processing this method.
7412  */
7413 int
7414 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
7415                    MonoInst *return_var, MonoInst **inline_args, 
7416                    guint inline_offset, gboolean is_virtual_call)
7417 {
7418         MonoError error;
7419         MonoInst *ins, **sp, **stack_start;
7420         MonoBasicBlock *tblock = NULL, *init_localsbb = NULL;
7421         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
7422         MonoMethod *cmethod, *method_definition;
7423         MonoInst **arg_array;
7424         MonoMethodHeader *header;
7425         MonoImage *image;
7426         guint32 token, ins_flag;
7427         MonoClass *klass;
7428         MonoClass *constrained_class = NULL;
7429         unsigned char *ip, *end, *target, *err_pos;
7430         MonoMethodSignature *sig;
7431         MonoGenericContext *generic_context = NULL;
7432         MonoGenericContainer *generic_container = NULL;
7433         MonoType **param_types;
7434         int i, n, start_new_bblock, dreg;
7435         int num_calls = 0, inline_costs = 0;
7436         int breakpoint_id = 0;
7437         guint num_args;
7438         GSList *class_inits = NULL;
7439         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
7440         int context_used;
7441         gboolean init_locals, seq_points, skip_dead_blocks;
7442         gboolean sym_seq_points = FALSE;
7443         MonoDebugMethodInfo *minfo;
7444         MonoBitSet *seq_point_locs = NULL;
7445         MonoBitSet *seq_point_set_locs = NULL;
7446
7447         cfg->disable_inline = is_jit_optimizer_disabled (method);
7448
7449         /* serialization and xdomain stuff may need access to private fields and methods */
7450         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
7451         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
7452         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
7453         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
7454         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
7455         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
7456
7457         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
7458         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
7459         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
7460         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
7461         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
7462
7463         image = method->klass->image;
7464         header = mono_method_get_header_checked (method, &cfg->error);
7465         if (!header) {
7466                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
7467                 goto exception_exit;
7468         } else {
7469                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
7470         }
7471
7472         generic_container = mono_method_get_generic_container (method);
7473         sig = mono_method_signature (method);
7474         num_args = sig->hasthis + sig->param_count;
7475         ip = (unsigned char*)header->code;
7476         cfg->cil_start = ip;
7477         end = ip + header->code_size;
7478         cfg->stat_cil_code_size += header->code_size;
7479
7480         seq_points = cfg->gen_seq_points && cfg->method == method;
7481
7482         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
7483                 /* We could hit a seq point before attaching to the JIT (#8338) */
7484                 seq_points = FALSE;
7485         }
7486
7487         if (cfg->gen_sdb_seq_points && cfg->method == method) {
7488                 minfo = mono_debug_lookup_method (method);
7489                 if (minfo) {
7490                         MonoSymSeqPoint *sps;
7491                         int i, n_il_offsets;
7492
7493                         mono_debug_get_seq_points (minfo, NULL, NULL, NULL, &sps, &n_il_offsets);
7494                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7495                         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);
7496                         sym_seq_points = TRUE;
7497                         for (i = 0; i < n_il_offsets; ++i) {
7498                                 if (sps [i].il_offset < header->code_size)
7499                                         mono_bitset_set_fast (seq_point_locs, sps [i].il_offset);
7500                         }
7501                         g_free (sps);
7502                 } else if (!method->wrapper_type && !method->dynamic && mono_debug_image_has_debug_info (method->klass->image)) {
7503                         /* Methods without line number info like auto-generated property accessors */
7504                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7505                         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);
7506                         sym_seq_points = TRUE;
7507                 }
7508         }
7509
7510         /* 
7511          * Methods without init_locals set could cause asserts in various passes
7512          * (#497220). To work around this, we emit dummy initialization opcodes
7513          * (OP_DUMMY_ICONST etc.) which generate no code. These are only supported
7514          * on some platforms.
7515          */
7516         if ((cfg->opt & MONO_OPT_UNSAFE) && cfg->backend->have_dummy_init)
7517                 init_locals = header->init_locals;
7518         else
7519                 init_locals = TRUE;
7520
7521         method_definition = method;
7522         while (method_definition->is_inflated) {
7523                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
7524                 method_definition = imethod->declaring;
7525         }
7526
7527         /* SkipVerification is not allowed if core-clr is enabled */
7528         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
7529                 dont_verify = TRUE;
7530                 dont_verify_stloc = TRUE;
7531         }
7532
7533         if (sig->is_inflated)
7534                 generic_context = mono_method_get_context (method);
7535         else if (generic_container)
7536                 generic_context = &generic_container->context;
7537         cfg->generic_context = generic_context;
7538
7539         if (!cfg->gshared)
7540                 g_assert (!sig->has_type_parameters);
7541
7542         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
7543                 g_assert (method->is_inflated);
7544                 g_assert (mono_method_get_context (method)->method_inst);
7545         }
7546         if (method->is_inflated && mono_method_get_context (method)->method_inst)
7547                 g_assert (sig->generic_param_count);
7548
7549         if (cfg->method == method) {
7550                 cfg->real_offset = 0;
7551         } else {
7552                 cfg->real_offset = inline_offset;
7553         }
7554
7555         cfg->cil_offset_to_bb = (MonoBasicBlock **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
7556         cfg->cil_offset_to_bb_len = header->code_size;
7557
7558         cfg->current_method = method;
7559
7560         if (cfg->verbose_level > 2)
7561                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
7562
7563         param_types = (MonoType **)mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
7564         if (sig->hasthis)
7565                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
7566         for (n = 0; n < sig->param_count; ++n)
7567                 param_types [n + sig->hasthis] = sig->params [n];
7568         cfg->arg_types = param_types;
7569
7570         cfg->dont_inline = g_list_prepend (cfg->dont_inline, method);
7571         if (cfg->method == method) {
7572
7573                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
7574                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
7575
7576                 /* ENTRY BLOCK */
7577                 NEW_BBLOCK (cfg, start_bblock);
7578                 cfg->bb_entry = start_bblock;
7579                 start_bblock->cil_code = NULL;
7580                 start_bblock->cil_length = 0;
7581
7582                 /* EXIT BLOCK */
7583                 NEW_BBLOCK (cfg, end_bblock);
7584                 cfg->bb_exit = end_bblock;
7585                 end_bblock->cil_code = NULL;
7586                 end_bblock->cil_length = 0;
7587                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
7588                 g_assert (cfg->num_bblocks == 2);
7589
7590                 arg_array = cfg->args;
7591
7592                 if (header->num_clauses) {
7593                         cfg->spvars = g_hash_table_new (NULL, NULL);
7594                         cfg->exvars = g_hash_table_new (NULL, NULL);
7595                 }
7596                 /* handle exception clauses */
7597                 for (i = 0; i < header->num_clauses; ++i) {
7598                         MonoBasicBlock *try_bb;
7599                         MonoExceptionClause *clause = &header->clauses [i];
7600                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
7601
7602                         try_bb->real_offset = clause->try_offset;
7603                         try_bb->try_start = TRUE;
7604                         try_bb->region = ((i + 1) << 8) | clause->flags;
7605                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
7606                         tblock->real_offset = clause->handler_offset;
7607                         tblock->flags |= BB_EXCEPTION_HANDLER;
7608
7609                         /*
7610                          * Linking the try block with the EH block hinders inlining as we won't be able to 
7611                          * merge the bblocks from inlining and produce an artificial hole for no good reason.
7612                          */
7613                         if (COMPILE_LLVM (cfg))
7614                                 link_bblock (cfg, try_bb, tblock);
7615
7616                         if (*(ip + clause->handler_offset) == CEE_POP)
7617                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
7618
7619                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
7620                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
7621                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
7622                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
7623                                 MONO_ADD_INS (tblock, ins);
7624
7625                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FILTER) {
7626                                         /* finally clauses already have a seq point */
7627                                         /* seq points for filter clauses are emitted below */
7628                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
7629                                         MONO_ADD_INS (tblock, ins);
7630                                 }
7631
7632                                 /* todo: is a fault block unsafe to optimize? */
7633                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
7634                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
7635                         }
7636
7637                         /*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);
7638                           while (p < end) {
7639                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
7640                           }*/
7641                         /* catch and filter blocks get the exception object on the stack */
7642                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
7643                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7644
7645                                 /* mostly like handle_stack_args (), but just sets the input args */
7646                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
7647                                 tblock->in_scount = 1;
7648                                 tblock->in_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7649                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7650
7651                                 cfg->cbb = tblock;
7652
7653 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
7654                                 /* The EH code passes in the exception in a register to both JITted and LLVM compiled code */
7655                                 if (!cfg->compile_llvm) {
7656                                         MONO_INST_NEW (cfg, ins, OP_GET_EX_OBJ);
7657                                         ins->dreg = tblock->in_stack [0]->dreg;
7658                                         MONO_ADD_INS (tblock, ins);
7659                                 }
7660 #else
7661                                 MonoInst *dummy_use;
7662
7663                                 /* 
7664                                  * Add a dummy use for the exvar so its liveness info will be
7665                                  * correct.
7666                                  */
7667                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
7668 #endif
7669
7670                                 if (seq_points && clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7671                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
7672                                         MONO_ADD_INS (tblock, ins);
7673                                 }
7674                                 
7675                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7676                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
7677                                         tblock->flags |= BB_EXCEPTION_HANDLER;
7678                                         tblock->real_offset = clause->data.filter_offset;
7679                                         tblock->in_scount = 1;
7680                                         tblock->in_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7681                                         /* The filter block shares the exvar with the handler block */
7682                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7683                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
7684                                         MONO_ADD_INS (tblock, ins);
7685                                 }
7686                         }
7687
7688                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
7689                                         clause->data.catch_class &&
7690                                         cfg->gshared &&
7691                                         mono_class_check_context_used (clause->data.catch_class)) {
7692                                 /*
7693                                  * In shared generic code with catch
7694                                  * clauses containing type variables
7695                                  * the exception handling code has to
7696                                  * be able to get to the rgctx.
7697                                  * Therefore we have to make sure that
7698                                  * the vtable/mrgctx argument (for
7699                                  * static or generic methods) or the
7700                                  * "this" argument (for non-static
7701                                  * methods) are live.
7702                                  */
7703                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
7704                                                 mini_method_get_context (method)->method_inst ||
7705                                                 method->klass->valuetype) {
7706                                         mono_get_vtable_var (cfg);
7707                                 } else {
7708                                         MonoInst *dummy_use;
7709
7710                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
7711                                 }
7712                         }
7713                 }
7714         } else {
7715                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
7716                 cfg->cbb = start_bblock;
7717                 cfg->args = arg_array;
7718                 mono_save_args (cfg, sig, inline_args);
7719         }
7720
7721         /* FIRST CODE BLOCK */
7722         NEW_BBLOCK (cfg, tblock);
7723         tblock->cil_code = ip;
7724         cfg->cbb = tblock;
7725         cfg->ip = ip;
7726
7727         ADD_BBLOCK (cfg, tblock);
7728
7729         if (cfg->method == method) {
7730                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
7731                 if (breakpoint_id) {
7732                         MONO_INST_NEW (cfg, ins, OP_BREAK);
7733                         MONO_ADD_INS (cfg->cbb, ins);
7734                 }
7735         }
7736
7737         /* we use a separate basic block for the initialization code */
7738         NEW_BBLOCK (cfg, init_localsbb);
7739         if (cfg->method == method)
7740                 cfg->bb_init = init_localsbb;
7741         init_localsbb->real_offset = cfg->real_offset;
7742         start_bblock->next_bb = init_localsbb;
7743         init_localsbb->next_bb = cfg->cbb;
7744         link_bblock (cfg, start_bblock, init_localsbb);
7745         link_bblock (cfg, init_localsbb, cfg->cbb);
7746                 
7747         cfg->cbb = init_localsbb;
7748
7749         if (cfg->gsharedvt && cfg->method == method) {
7750                 MonoGSharedVtMethodInfo *info;
7751                 MonoInst *var, *locals_var;
7752                 int dreg;
7753
7754                 info = (MonoGSharedVtMethodInfo *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
7755                 info->method = cfg->method;
7756                 info->count_entries = 16;
7757                 info->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
7758                 cfg->gsharedvt_info = info;
7759
7760                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
7761                 /* prevent it from being register allocated */
7762                 //var->flags |= MONO_INST_VOLATILE;
7763                 cfg->gsharedvt_info_var = var;
7764
7765                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
7766                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
7767
7768                 /* Allocate locals */
7769                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
7770                 /* prevent it from being register allocated */
7771                 //locals_var->flags |= MONO_INST_VOLATILE;
7772                 cfg->gsharedvt_locals_var = locals_var;
7773
7774                 dreg = alloc_ireg (cfg);
7775                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
7776
7777                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
7778                 ins->dreg = locals_var->dreg;
7779                 ins->sreg1 = dreg;
7780                 MONO_ADD_INS (cfg->cbb, ins);
7781                 cfg->gsharedvt_locals_var_ins = ins;
7782                 
7783                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
7784                 /*
7785                 if (init_locals)
7786                         ins->flags |= MONO_INST_INIT;
7787                 */
7788         }
7789
7790         if (mono_security_core_clr_enabled ()) {
7791                 /* check if this is native code, e.g. an icall or a p/invoke */
7792                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
7793                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
7794                         if (wrapped) {
7795                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
7796                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
7797
7798                                 /* if this ia a native call then it can only be JITted from platform code */
7799                                 if ((icall || pinvk) && method->klass && method->klass->image) {
7800                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
7801                                                 MonoException *ex = icall ? mono_get_exception_security () : 
7802                                                         mono_get_exception_method_access ();
7803                                                 emit_throw_exception (cfg, ex);
7804                                         }
7805                                 }
7806                         }
7807                 }
7808         }
7809
7810         CHECK_CFG_EXCEPTION;
7811
7812         if (header->code_size == 0)
7813                 UNVERIFIED;
7814
7815         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
7816                 ip = err_pos;
7817                 UNVERIFIED;
7818         }
7819
7820         if (cfg->method == method)
7821                 mono_debug_init_method (cfg, cfg->cbb, breakpoint_id);
7822
7823         for (n = 0; n < header->num_locals; ++n) {
7824                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
7825                         UNVERIFIED;
7826         }
7827         class_inits = NULL;
7828
7829         /* We force the vtable variable here for all shared methods
7830            for the possibility that they might show up in a stack
7831            trace where their exact instantiation is needed. */
7832         if (cfg->gshared && method == cfg->method) {
7833                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
7834                                 mini_method_get_context (method)->method_inst ||
7835                                 method->klass->valuetype) {
7836                         mono_get_vtable_var (cfg);
7837                 } else {
7838                         /* FIXME: Is there a better way to do this?
7839                            We need the variable live for the duration
7840                            of the whole method. */
7841                         cfg->args [0]->flags |= MONO_INST_VOLATILE;
7842                 }
7843         }
7844
7845         /* add a check for this != NULL to inlined methods */
7846         if (is_virtual_call) {
7847                 MonoInst *arg_ins;
7848
7849                 NEW_ARGLOAD (cfg, arg_ins, 0);
7850                 MONO_ADD_INS (cfg->cbb, arg_ins);
7851                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
7852         }
7853
7854         skip_dead_blocks = !dont_verify;
7855         if (skip_dead_blocks) {
7856                 original_bb = bb = mono_basic_block_split (method, &cfg->error, header);
7857                 CHECK_CFG_ERROR;
7858                 g_assert (bb);
7859         }
7860
7861         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
7862         stack_start = sp = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
7863
7864         ins_flag = 0;
7865         start_new_bblock = 0;
7866         while (ip < end) {
7867                 if (cfg->method == method)
7868                         cfg->real_offset = ip - header->code;
7869                 else
7870                         cfg->real_offset = inline_offset;
7871                 cfg->ip = ip;
7872
7873                 context_used = 0;
7874
7875                 if (start_new_bblock) {
7876                         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
7877                         if (start_new_bblock == 2) {
7878                                 g_assert (ip == tblock->cil_code);
7879                         } else {
7880                                 GET_BBLOCK (cfg, tblock, ip);
7881                         }
7882                         cfg->cbb->next_bb = tblock;
7883                         cfg->cbb = tblock;
7884                         start_new_bblock = 0;
7885                         for (i = 0; i < cfg->cbb->in_scount; ++i) {
7886                                 if (cfg->verbose_level > 3)
7887                                         printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
7888                                 EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
7889                                 *sp++ = ins;
7890                         }
7891                         if (class_inits)
7892                                 g_slist_free (class_inits);
7893                         class_inits = NULL;
7894                 } else {
7895                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != cfg->cbb)) {
7896                                 link_bblock (cfg, cfg->cbb, tblock);
7897                                 if (sp != stack_start) {
7898                                         handle_stack_args (cfg, stack_start, sp - stack_start);
7899                                         sp = stack_start;
7900                                         CHECK_UNVERIFIABLE (cfg);
7901                                 }
7902                                 cfg->cbb->next_bb = tblock;
7903                                 cfg->cbb = tblock;
7904                                 for (i = 0; i < cfg->cbb->in_scount; ++i) {
7905                                         if (cfg->verbose_level > 3)
7906                                                 printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
7907                                         EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
7908                                         *sp++ = ins;
7909                                 }
7910                                 g_slist_free (class_inits);
7911                                 class_inits = NULL;
7912                         }
7913                 }
7914
7915                 if (skip_dead_blocks) {
7916                         int ip_offset = ip - header->code;
7917
7918                         if (ip_offset == bb->end)
7919                                 bb = bb->next;
7920
7921                         if (bb->dead) {
7922                                 int op_size = mono_opcode_size (ip, end);
7923                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
7924
7925                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
7926
7927                                 if (ip_offset + op_size == bb->end) {
7928                                         MONO_INST_NEW (cfg, ins, OP_NOP);
7929                                         MONO_ADD_INS (cfg->cbb, ins);
7930                                         start_new_bblock = 1;
7931                                 }
7932
7933                                 ip += op_size;
7934                                 continue;
7935                         }
7936                 }
7937                 /*
7938                  * Sequence points are points where the debugger can place a breakpoint.
7939                  * Currently, we generate these automatically at points where the IL
7940                  * stack is empty.
7941                  */
7942                 if (seq_points && ((!sym_seq_points && (sp == stack_start)) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
7943                         /*
7944                          * Make methods interruptable at the beginning, and at the targets of
7945                          * backward branches.
7946                          * Also, do this at the start of every bblock in methods with clauses too,
7947                          * to be able to handle instructions with inprecise control flow like
7948                          * throw/endfinally.
7949                          * Backward branches are handled at the end of method-to-ir ().
7950                          */
7951                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
7952                         gboolean sym_seq_point = sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code);
7953
7954                         /* Avoid sequence points on empty IL like .volatile */
7955                         // FIXME: Enable this
7956                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
7957                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
7958                         if ((sp != stack_start) && !sym_seq_point)
7959                                 ins->flags |= MONO_INST_NONEMPTY_STACK;
7960                         MONO_ADD_INS (cfg->cbb, ins);
7961
7962                         if (sym_seq_points)
7963                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
7964                 }
7965
7966                 cfg->cbb->real_offset = cfg->real_offset;
7967
7968                 if ((cfg->method == method) && cfg->coverage_info) {
7969                         guint32 cil_offset = ip - header->code;
7970                         cfg->coverage_info->data [cil_offset].cil_code = ip;
7971
7972                         /* TODO: Use an increment here */
7973 #if defined(TARGET_X86)
7974                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
7975                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
7976                         ins->inst_imm = 1;
7977                         MONO_ADD_INS (cfg->cbb, ins);
7978 #else
7979                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
7980                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
7981 #endif
7982                 }
7983
7984                 if (cfg->verbose_level > 3)
7985                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
7986
7987                 switch (*ip) {
7988                 case CEE_NOP:
7989                         if (seq_points && !sym_seq_points && sp != stack_start) {
7990                                 /*
7991                                  * The C# compiler uses these nops to notify the JIT that it should
7992                                  * insert seq points.
7993                                  */
7994                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
7995                                 MONO_ADD_INS (cfg->cbb, ins);
7996                         }
7997                         if (cfg->keep_cil_nops)
7998                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
7999                         else
8000                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8001                         ip++;
8002                         MONO_ADD_INS (cfg->cbb, ins);
8003                         break;
8004                 case CEE_BREAK:
8005                         if (should_insert_brekpoint (cfg->method)) {
8006                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
8007                         } else {
8008                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8009                         }
8010                         ip++;
8011                         MONO_ADD_INS (cfg->cbb, ins);
8012                         break;
8013                 case CEE_LDARG_0:
8014                 case CEE_LDARG_1:
8015                 case CEE_LDARG_2:
8016                 case CEE_LDARG_3:
8017                         CHECK_STACK_OVF (1);
8018                         n = (*ip)-CEE_LDARG_0;
8019                         CHECK_ARG (n);
8020                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8021                         ip++;
8022                         *sp++ = ins;
8023                         break;
8024                 case CEE_LDLOC_0:
8025                 case CEE_LDLOC_1:
8026                 case CEE_LDLOC_2:
8027                 case CEE_LDLOC_3:
8028                         CHECK_STACK_OVF (1);
8029                         n = (*ip)-CEE_LDLOC_0;
8030                         CHECK_LOCAL (n);
8031                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8032                         ip++;
8033                         *sp++ = ins;
8034                         break;
8035                 case CEE_STLOC_0:
8036                 case CEE_STLOC_1:
8037                 case CEE_STLOC_2:
8038                 case CEE_STLOC_3: {
8039                         CHECK_STACK (1);
8040                         n = (*ip)-CEE_STLOC_0;
8041                         CHECK_LOCAL (n);
8042                         --sp;
8043                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
8044                                 UNVERIFIED;
8045                         emit_stloc_ir (cfg, sp, header, n);
8046                         ++ip;
8047                         inline_costs += 1;
8048                         break;
8049                         }
8050                 case CEE_LDARG_S:
8051                         CHECK_OPSIZE (2);
8052                         CHECK_STACK_OVF (1);
8053                         n = ip [1];
8054                         CHECK_ARG (n);
8055                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8056                         *sp++ = ins;
8057                         ip += 2;
8058                         break;
8059                 case CEE_LDARGA_S:
8060                         CHECK_OPSIZE (2);
8061                         CHECK_STACK_OVF (1);
8062                         n = ip [1];
8063                         CHECK_ARG (n);
8064                         NEW_ARGLOADA (cfg, ins, n);
8065                         MONO_ADD_INS (cfg->cbb, ins);
8066                         *sp++ = ins;
8067                         ip += 2;
8068                         break;
8069                 case CEE_STARG_S:
8070                         CHECK_OPSIZE (2);
8071                         CHECK_STACK (1);
8072                         --sp;
8073                         n = ip [1];
8074                         CHECK_ARG (n);
8075                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
8076                                 UNVERIFIED;
8077                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
8078                         ip += 2;
8079                         break;
8080                 case CEE_LDLOC_S:
8081                         CHECK_OPSIZE (2);
8082                         CHECK_STACK_OVF (1);
8083                         n = ip [1];
8084                         CHECK_LOCAL (n);
8085                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8086                         *sp++ = ins;
8087                         ip += 2;
8088                         break;
8089                 case CEE_LDLOCA_S: {
8090                         unsigned char *tmp_ip;
8091                         CHECK_OPSIZE (2);
8092                         CHECK_STACK_OVF (1);
8093                         CHECK_LOCAL (ip [1]);
8094
8095                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
8096                                 ip = tmp_ip;
8097                                 inline_costs += 1;
8098                                 break;
8099                         }
8100
8101                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
8102                         *sp++ = ins;
8103                         ip += 2;
8104                         break;
8105                 }
8106                 case CEE_STLOC_S:
8107                         CHECK_OPSIZE (2);
8108                         CHECK_STACK (1);
8109                         --sp;
8110                         CHECK_LOCAL (ip [1]);
8111                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
8112                                 UNVERIFIED;
8113                         emit_stloc_ir (cfg, sp, header, ip [1]);
8114                         ip += 2;
8115                         inline_costs += 1;
8116                         break;
8117                 case CEE_LDNULL:
8118                         CHECK_STACK_OVF (1);
8119                         EMIT_NEW_PCONST (cfg, ins, NULL);
8120                         ins->type = STACK_OBJ;
8121                         ++ip;
8122                         *sp++ = ins;
8123                         break;
8124                 case CEE_LDC_I4_M1:
8125                         CHECK_STACK_OVF (1);
8126                         EMIT_NEW_ICONST (cfg, ins, -1);
8127                         ++ip;
8128                         *sp++ = ins;
8129                         break;
8130                 case CEE_LDC_I4_0:
8131                 case CEE_LDC_I4_1:
8132                 case CEE_LDC_I4_2:
8133                 case CEE_LDC_I4_3:
8134                 case CEE_LDC_I4_4:
8135                 case CEE_LDC_I4_5:
8136                 case CEE_LDC_I4_6:
8137                 case CEE_LDC_I4_7:
8138                 case CEE_LDC_I4_8:
8139                         CHECK_STACK_OVF (1);
8140                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
8141                         ++ip;
8142                         *sp++ = ins;
8143                         break;
8144                 case CEE_LDC_I4_S:
8145                         CHECK_OPSIZE (2);
8146                         CHECK_STACK_OVF (1);
8147                         ++ip;
8148                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
8149                         ++ip;
8150                         *sp++ = ins;
8151                         break;
8152                 case CEE_LDC_I4:
8153                         CHECK_OPSIZE (5);
8154                         CHECK_STACK_OVF (1);
8155                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
8156                         ip += 5;
8157                         *sp++ = ins;
8158                         break;
8159                 case CEE_LDC_I8:
8160                         CHECK_OPSIZE (9);
8161                         CHECK_STACK_OVF (1);
8162                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
8163                         ins->type = STACK_I8;
8164                         ins->dreg = alloc_dreg (cfg, STACK_I8);
8165                         ++ip;
8166                         ins->inst_l = (gint64)read64 (ip);
8167                         MONO_ADD_INS (cfg->cbb, ins);
8168                         ip += 8;
8169                         *sp++ = ins;
8170                         break;
8171                 case CEE_LDC_R4: {
8172                         float *f;
8173                         gboolean use_aotconst = FALSE;
8174
8175 #ifdef TARGET_POWERPC
8176                         /* FIXME: Clean this up */
8177                         if (cfg->compile_aot)
8178                                 use_aotconst = TRUE;
8179 #endif
8180
8181                         /* FIXME: we should really allocate this only late in the compilation process */
8182                         f = (float *)mono_domain_alloc (cfg->domain, sizeof (float));
8183                         CHECK_OPSIZE (5);
8184                         CHECK_STACK_OVF (1);
8185
8186                         if (use_aotconst) {
8187                                 MonoInst *cons;
8188                                 int dreg;
8189
8190                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
8191
8192                                 dreg = alloc_freg (cfg);
8193                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
8194                                 ins->type = cfg->r4_stack_type;
8195                         } else {
8196                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
8197                                 ins->type = cfg->r4_stack_type;
8198                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8199                                 ins->inst_p0 = f;
8200                                 MONO_ADD_INS (cfg->cbb, ins);
8201                         }
8202                         ++ip;
8203                         readr4 (ip, f);
8204                         ip += 4;
8205                         *sp++ = ins;                    
8206                         break;
8207                 }
8208                 case CEE_LDC_R8: {
8209                         double *d;
8210                         gboolean use_aotconst = FALSE;
8211
8212 #ifdef TARGET_POWERPC
8213                         /* FIXME: Clean this up */
8214                         if (cfg->compile_aot)
8215                                 use_aotconst = TRUE;
8216 #endif
8217
8218                         /* FIXME: we should really allocate this only late in the compilation process */
8219                         d = (double *)mono_domain_alloc (cfg->domain, sizeof (double));
8220                         CHECK_OPSIZE (9);
8221                         CHECK_STACK_OVF (1);
8222
8223                         if (use_aotconst) {
8224                                 MonoInst *cons;
8225                                 int dreg;
8226
8227                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
8228
8229                                 dreg = alloc_freg (cfg);
8230                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
8231                                 ins->type = STACK_R8;
8232                         } else {
8233                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
8234                                 ins->type = STACK_R8;
8235                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8236                                 ins->inst_p0 = d;
8237                                 MONO_ADD_INS (cfg->cbb, ins);
8238                         }
8239                         ++ip;
8240                         readr8 (ip, d);
8241                         ip += 8;
8242                         *sp++ = ins;
8243                         break;
8244                 }
8245                 case CEE_DUP: {
8246                         MonoInst *temp, *store;
8247                         CHECK_STACK (1);
8248                         CHECK_STACK_OVF (1);
8249                         sp--;
8250                         ins = *sp;
8251
8252                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
8253                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
8254
8255                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8256                         *sp++ = ins;
8257
8258                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8259                         *sp++ = ins;
8260
8261                         ++ip;
8262                         inline_costs += 2;
8263                         break;
8264                 }
8265                 case CEE_POP:
8266                         CHECK_STACK (1);
8267                         ip++;
8268                         --sp;
8269
8270 #ifdef TARGET_X86
8271                         if (sp [0]->type == STACK_R8)
8272                                 /* we need to pop the value from the x86 FP stack */
8273                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
8274 #endif
8275                         break;
8276                 case CEE_JMP: {
8277                         MonoCallInst *call;
8278                         MonoMethodSignature *fsig;
8279                         int i, n;
8280
8281                         INLINE_FAILURE ("jmp");
8282                         GSHAREDVT_FAILURE (*ip);
8283
8284                         CHECK_OPSIZE (5);
8285                         if (stack_start != sp)
8286                                 UNVERIFIED;
8287                         token = read32 (ip + 1);
8288                         /* FIXME: check the signature matches */
8289                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8290                         CHECK_CFG_ERROR;
8291  
8292                         if (cfg->gshared && mono_method_check_context_used (cmethod))
8293                                 GENERIC_SHARING_FAILURE (CEE_JMP);
8294
8295                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
8296
8297                         fsig = mono_method_signature (cmethod);
8298                         n = fsig->param_count + fsig->hasthis;
8299                         if (cfg->llvm_only) {
8300                                 MonoInst **args;
8301
8302                                 args = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
8303                                 for (i = 0; i < n; ++i)
8304                                         EMIT_NEW_ARGLOAD (cfg, args [i], i);
8305                                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, TRUE, args, NULL, NULL, NULL);
8306                                 /*
8307                                  * The code in mono-basic-block.c treats the rest of the code as dead, but we
8308                                  * have to emit a normal return since llvm expects it.
8309                                  */
8310                                 if (cfg->ret)
8311                                         emit_setret (cfg, ins);
8312                                 MONO_INST_NEW (cfg, ins, OP_BR);
8313                                 ins->inst_target_bb = end_bblock;
8314                                 MONO_ADD_INS (cfg->cbb, ins);
8315                                 link_bblock (cfg, cfg->cbb, end_bblock);
8316                                 ip += 5;
8317                                 break;
8318                         } else if (cfg->backend->have_op_tail_call) {
8319                                 /* Handle tail calls similarly to calls */
8320                                 DISABLE_AOT (cfg);
8321
8322                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
8323                                 call->method = cmethod;
8324                                 call->tail_call = TRUE;
8325                                 call->signature = mono_method_signature (cmethod);
8326                                 call->args = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
8327                                 call->inst.inst_p0 = cmethod;
8328                                 for (i = 0; i < n; ++i)
8329                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
8330
8331                                 if (mini_type_is_vtype (mini_get_underlying_type (call->signature->ret)))
8332                                         call->vret_var = cfg->vret_addr;
8333
8334                                 mono_arch_emit_call (cfg, call);
8335                                 cfg->param_area = MAX(cfg->param_area, call->stack_usage);
8336                                 MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
8337                         } else {
8338                                 for (i = 0; i < num_args; ++i)
8339                                         /* Prevent arguments from being optimized away */
8340                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
8341
8342                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
8343                                 ins = (MonoInst*)call;
8344                                 ins->inst_p0 = cmethod;
8345                                 MONO_ADD_INS (cfg->cbb, ins);
8346                         }
8347
8348                         ip += 5;
8349                         start_new_bblock = 1;
8350                         break;
8351                 }
8352                 case CEE_CALLI: {
8353                         MonoInst *addr;
8354                         MonoMethodSignature *fsig;
8355
8356                         CHECK_OPSIZE (5);
8357                         token = read32 (ip + 1);
8358
8359                         ins = NULL;
8360
8361                         //GSHAREDVT_FAILURE (*ip);
8362                         cmethod = NULL;
8363                         CHECK_STACK (1);
8364                         --sp;
8365                         addr = *sp;
8366                         fsig = mini_get_signature (method, token, generic_context, &cfg->error);
8367                         CHECK_CFG_ERROR;
8368
8369                         if (method->dynamic && fsig->pinvoke) {
8370                                 MonoInst *args [3];
8371
8372                                 /*
8373                                  * This is a call through a function pointer using a pinvoke
8374                                  * signature. Have to create a wrapper and call that instead.
8375                                  * FIXME: This is very slow, need to create a wrapper at JIT time
8376                                  * instead based on the signature.
8377                                  */
8378                                 EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
8379                                 EMIT_NEW_PCONST (cfg, args [1], fsig);
8380                                 args [2] = addr;
8381                                 addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
8382                         }
8383
8384                         n = fsig->param_count + fsig->hasthis;
8385
8386                         CHECK_STACK (n);
8387
8388                         //g_assert (!virtual_ || fsig->hasthis);
8389
8390                         sp -= n;
8391
8392                         inline_costs += 10 * num_calls++;
8393
8394                         /*
8395                          * Making generic calls out of gsharedvt methods.
8396                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
8397                          * patching gshared method addresses into a gsharedvt method.
8398                          */
8399                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
8400                                 /*
8401                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
8402                                  */
8403                                 MonoInst *callee = addr;
8404
8405                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
8406                                         /* Not tested */
8407                                         GSHAREDVT_FAILURE (*ip);
8408
8409                                 if (cfg->llvm_only)
8410                                         // FIXME:
8411                                         GSHAREDVT_FAILURE (*ip);
8412
8413                                 addr = emit_get_rgctx_sig (cfg, context_used,
8414                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
8415                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
8416                                 goto calli_end;
8417                         }
8418
8419                         /* Prevent inlining of methods with indirect calls */
8420                         INLINE_FAILURE ("indirect call");
8421
8422                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
8423                                 MonoJumpInfoType info_type;
8424                                 gpointer info_data;
8425
8426                                 /*
8427                                  * Instead of emitting an indirect call, emit a direct call
8428                                  * with the contents of the aotconst as the patch info.
8429                                  */
8430                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
8431                                         info_type = (MonoJumpInfoType)addr->inst_c1;
8432                                         info_data = addr->inst_p0;
8433                                 } else {
8434                                         info_type = (MonoJumpInfoType)addr->inst_right->inst_c1;
8435                                         info_data = addr->inst_right->inst_left;
8436                                 }
8437
8438                                 if (info_type == MONO_PATCH_INFO_ICALL_ADDR) {
8439                                         ins = (MonoInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_ICALL_ADDR_CALL, info_data, fsig, sp);
8440                                         NULLIFY_INS (addr);
8441                                         goto calli_end;
8442                                 } else if (info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
8443                                         ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
8444                                         NULLIFY_INS (addr);
8445                                         goto calli_end;
8446                                 }
8447                         }
8448                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8449
8450                         calli_end:
8451
8452                         /* End of call, INS should contain the result of the call, if any */
8453
8454                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8455                                 g_assert (ins);
8456                                 *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
8457                         }
8458
8459                         CHECK_CFG_EXCEPTION;
8460
8461                         ip += 5;
8462                         ins_flag = 0;
8463                         constrained_class = NULL;
8464                         break;
8465                 }
8466                 case CEE_CALL:
8467                 case CEE_CALLVIRT: {
8468                         MonoInst *addr = NULL;
8469                         MonoMethodSignature *fsig = NULL;
8470                         int array_rank = 0;
8471                         int virtual_ = *ip == CEE_CALLVIRT;
8472                         gboolean pass_imt_from_rgctx = FALSE;
8473                         MonoInst *imt_arg = NULL;
8474                         MonoInst *keep_this_alive = NULL;
8475                         gboolean pass_vtable = FALSE;
8476                         gboolean pass_mrgctx = FALSE;
8477                         MonoInst *vtable_arg = NULL;
8478                         gboolean check_this = FALSE;
8479                         gboolean supported_tail_call = FALSE;
8480                         gboolean tail_call = FALSE;
8481                         gboolean need_seq_point = FALSE;
8482                         guint32 call_opcode = *ip;
8483                         gboolean emit_widen = TRUE;
8484                         gboolean push_res = TRUE;
8485                         gboolean skip_ret = FALSE;
8486                         gboolean delegate_invoke = FALSE;
8487                         gboolean direct_icall = FALSE;
8488                         gboolean constrained_partial_call = FALSE;
8489                         MonoMethod *cil_method;
8490
8491                         CHECK_OPSIZE (5);
8492                         token = read32 (ip + 1);
8493
8494                         ins = NULL;
8495
8496                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8497                         CHECK_CFG_ERROR;
8498
8499                         cil_method = cmethod;
8500                                 
8501                         if (constrained_class) {
8502                                 if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
8503                                         if (!mini_is_gsharedvt_klass (constrained_class)) {
8504                                                 g_assert (!cmethod->klass->valuetype);
8505                                                 if (!mini_type_is_reference (&constrained_class->byval_arg))
8506                                                         constrained_partial_call = TRUE;
8507                                         }
8508                                 }
8509
8510                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
8511                                         if (cfg->verbose_level > 2)
8512                                                 printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_class));
8513                                         if (!((constrained_class->byval_arg.type == MONO_TYPE_VAR ||
8514                                                    constrained_class->byval_arg.type == MONO_TYPE_MVAR) &&
8515                                                   cfg->gshared)) {
8516                                                 cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_class, generic_context, &cfg->error);
8517                                                 CHECK_CFG_ERROR;
8518                                         }
8519                                 } else {
8520                                         if (cfg->verbose_level > 2)
8521                                                 printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_class));
8522
8523                                         if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
8524                                                 /* 
8525                                                  * This is needed since get_method_constrained can't find 
8526                                                  * the method in klass representing a type var.
8527                                                  * The type var is guaranteed to be a reference type in this
8528                                                  * case.
8529                                                  */
8530                                                 if (!mini_is_gsharedvt_klass (constrained_class))
8531                                                         g_assert (!cmethod->klass->valuetype);
8532                                         } else {
8533                                                 cmethod = mono_get_method_constrained_checked (image, token, constrained_class, generic_context, &cil_method, &cfg->error);
8534                                                 CHECK_CFG_ERROR;
8535                                         }
8536                                 }
8537                         }
8538                                         
8539                         if (!dont_verify && !cfg->skip_visibility) {
8540                                 MonoMethod *target_method = cil_method;
8541                                 if (method->is_inflated) {
8542                                         target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context), &cfg->error);
8543                                         CHECK_CFG_ERROR;
8544                                 }
8545                                 if (!mono_method_can_access_method (method_definition, target_method) &&
8546                                         !mono_method_can_access_method (method, cil_method))
8547                                         emit_method_access_failure (cfg, method, cil_method);
8548                         }
8549
8550                         if (mono_security_core_clr_enabled ())
8551                                 ensure_method_is_allowed_to_call_method (cfg, method, cil_method);
8552
8553                         if (!virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
8554                                 /* MS.NET seems to silently convert this to a callvirt */
8555                                 virtual_ = 1;
8556
8557                         {
8558                                 /*
8559                                  * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
8560                                  * converts to a callvirt.
8561                                  *
8562                                  * tests/bug-515884.il is an example of this behavior
8563                                  */
8564                                 const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
8565                                 const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
8566                                 if (!virtual_ && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
8567                                         virtual_ = 1;
8568                         }
8569
8570                         if (!cmethod->klass->inited)
8571                                 if (!mono_class_init (cmethod->klass))
8572                                         TYPE_LOAD_ERROR (cmethod->klass);
8573
8574                         fsig = mono_method_signature (cmethod);
8575                         if (!fsig)
8576                                 LOAD_ERROR;
8577                         if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
8578                                 mini_class_is_system_array (cmethod->klass)) {
8579                                 array_rank = cmethod->klass->rank;
8580                         } else if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && icall_is_direct_callable (cfg, cmethod)) {
8581                                 direct_icall = TRUE;
8582                         } else if (fsig->pinvoke) {
8583                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
8584                                 fsig = mono_method_signature (wrapper);
8585                         } else if (constrained_class) {
8586                         } else {
8587                                 fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
8588                                 CHECK_CFG_ERROR;
8589                         }
8590
8591                         if (cfg->llvm_only && !cfg->method->wrapper_type && (!cmethod || cmethod->is_inflated))
8592                                 cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
8593
8594                         /* See code below */
8595                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
8596                                 MonoBasicBlock *tbb;
8597
8598                                 GET_BBLOCK (cfg, tbb, ip + 5);
8599                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
8600                                         /*
8601                                          * We want to extend the try block to cover the call, but we can't do it if the
8602                                          * call is made directly since its followed by an exception check.
8603                                          */
8604                                         direct_icall = FALSE;
8605                                 }
8606                         }
8607
8608                         mono_save_token_info (cfg, image, token, cil_method);
8609
8610                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip + 5 - header->code)))
8611                                 need_seq_point = TRUE;
8612
8613                         /* Don't support calls made using type arguments for now */
8614                         /*
8615                           if (cfg->gsharedvt) {
8616                           if (mini_is_gsharedvt_signature (fsig))
8617                           GSHAREDVT_FAILURE (*ip);
8618                           }
8619                         */
8620
8621                         if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
8622                                 g_assert_not_reached ();
8623
8624                         n = fsig->param_count + fsig->hasthis;
8625
8626                         if (!cfg->gshared && mono_class_is_gtd (cmethod->klass))
8627                                 UNVERIFIED;
8628
8629                         if (!cfg->gshared)
8630                                 g_assert (!mono_method_check_context_used (cmethod));
8631
8632                         CHECK_STACK (n);
8633
8634                         //g_assert (!virtual_ || fsig->hasthis);
8635
8636                         sp -= n;
8637
8638                         /*
8639                          * We have the `constrained.' prefix opcode.
8640                          */
8641                         if (constrained_class) {
8642                                 if (mini_is_gsharedvt_klass (constrained_class)) {
8643                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_class->valuetype && cmethod->klass->valuetype) {
8644                                                 /* The 'Own method' case below */
8645                                         } else if (cmethod->klass->image != mono_defaults.corlib && !mono_class_is_interface (cmethod->klass) && !cmethod->klass->valuetype) {
8646                                                 /* 'The type parameter is instantiated as a reference type' case below. */
8647                                         } else {
8648                                                 ins = handle_constrained_gsharedvt_call (cfg, cmethod, fsig, sp, constrained_class, &emit_widen);
8649                                                 CHECK_CFG_EXCEPTION;
8650                                                 g_assert (ins);
8651                                                 goto call_end;
8652                                         }
8653                                 }
8654
8655                                 if (constrained_partial_call) {
8656                                         gboolean need_box = TRUE;
8657
8658                                         /*
8659                                          * The receiver is a valuetype, but the exact type is not known at compile time. This means the
8660                                          * called method is not known at compile time either. The called method could end up being
8661                                          * one of the methods on the parent classes (object/valuetype/enum), in which case we need
8662                                          * to box the receiver.
8663                                          * A simple solution would be to box always and make a normal virtual call, but that would
8664                                          * be bad performance wise.
8665                                          */
8666                                         if (mono_class_is_interface (cmethod->klass) && mono_class_is_ginst (cmethod->klass)) {
8667                                                 /*
8668                                                  * The parent classes implement no generic interfaces, so the called method will be a vtype method, so no boxing neccessary.
8669                                                  */
8670                                                 need_box = FALSE;
8671                                         }
8672
8673                                         if (!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
8674                                                 /* The called method is not virtual, i.e. Object:GetType (), the receiver is a vtype, has to box */
8675                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8676                                                 ins->klass = constrained_class;
8677                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8678                                                 CHECK_CFG_EXCEPTION;
8679                                         } else if (need_box) {
8680                                                 MonoInst *box_type;
8681                                                 MonoBasicBlock *is_ref_bb, *end_bb;
8682                                                 MonoInst *nonbox_call;
8683
8684                                                 /*
8685                                                  * Determine at runtime whenever the called method is defined on object/valuetype/enum, and emit a boxing call
8686                                                  * if needed.
8687                                                  * FIXME: It is possible to inline the called method in a lot of cases, i.e. for T_INT,
8688                                                  * the no-box case goes to a method in Int32, while the box case goes to a method in Enum.
8689                                                  */
8690                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
8691
8692                                                 NEW_BBLOCK (cfg, is_ref_bb);
8693                                                 NEW_BBLOCK (cfg, end_bb);
8694
8695                                                 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);
8696                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, box_type->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
8697                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
8698
8699                                                 /* Non-ref case */
8700                                                 nonbox_call = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8701
8702                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
8703
8704                                                 /* Ref case */
8705                                                 MONO_START_BB (cfg, is_ref_bb);
8706                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8707                                                 ins->klass = constrained_class;
8708                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8709                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8710
8711                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
8712
8713                                                 MONO_START_BB (cfg, end_bb);
8714                                                 cfg->cbb = end_bb;
8715
8716                                                 nonbox_call->dreg = ins->dreg;
8717                                                 goto call_end;
8718                                         } else {
8719                                                 g_assert (mono_class_is_interface (cmethod->klass));
8720                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
8721                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8722                                                 goto call_end;
8723                                         }
8724                                 } else if (constrained_class->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
8725                                         /*
8726                                          * The type parameter is instantiated as a valuetype,
8727                                          * but that type doesn't override the method we're
8728                                          * calling, so we need to box `this'.
8729                                          */
8730                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8731                                         ins->klass = constrained_class;
8732                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8733                                         CHECK_CFG_EXCEPTION;
8734                                 } else if (!constrained_class->valuetype) {
8735                                         int dreg = alloc_ireg_ref (cfg);
8736
8737                                         /*
8738                                          * The type parameter is instantiated as a reference
8739                                          * type.  We have a managed pointer on the stack, so
8740                                          * we need to dereference it here.
8741                                          */
8742                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
8743                                         ins->type = STACK_OBJ;
8744                                         sp [0] = ins;
8745                                 } else {
8746                                         if (cmethod->klass->valuetype) {
8747                                                 /* Own method */
8748                                         } else {
8749                                                 /* Interface method */
8750                                                 int ioffset, slot;
8751
8752                                                 mono_class_setup_vtable (constrained_class);
8753                                                 CHECK_TYPELOAD (constrained_class);
8754                                                 ioffset = mono_class_interface_offset (constrained_class, cmethod->klass);
8755                                                 if (ioffset == -1)
8756                                                         TYPE_LOAD_ERROR (constrained_class);
8757                                                 slot = mono_method_get_vtable_slot (cmethod);
8758                                                 if (slot == -1)
8759                                                         TYPE_LOAD_ERROR (cmethod->klass);
8760                                                 cmethod = constrained_class->vtable [ioffset + slot];
8761
8762                                                 if (cmethod->klass == mono_defaults.enum_class) {
8763                                                         /* Enum implements some interfaces, so treat this as the first case */
8764                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8765                                                         ins->klass = constrained_class;
8766                                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8767                                                         CHECK_CFG_EXCEPTION;
8768                                                 }
8769                                         }
8770                                         virtual_ = 0;
8771                                 }
8772                                 constrained_class = NULL;
8773                         }
8774
8775                         if (check_call_signature (cfg, fsig, sp))
8776                                 UNVERIFIED;
8777
8778                         if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
8779                                 delegate_invoke = TRUE;
8780
8781                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
8782                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8783                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
8784                                         emit_widen = FALSE;
8785                                 }
8786
8787                                 goto call_end;
8788                         }
8789
8790                         /* 
8791                          * If the callee is a shared method, then its static cctor
8792                          * might not get called after the call was patched.
8793                          */
8794                         if (cfg->gshared && cmethod->klass != method->klass && mono_class_is_ginst (cmethod->klass) && mono_method_is_generic_sharable (cmethod, TRUE) && mono_class_needs_cctor_run (cmethod->klass, method)) {
8795                                 emit_class_init (cfg, cmethod->klass);
8796                                 CHECK_TYPELOAD (cmethod->klass);
8797                         }
8798
8799                         check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
8800
8801                         if (cfg->gshared) {
8802                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
8803
8804                                 context_used = mini_method_check_context_used (cfg, cmethod);
8805
8806                                 if (context_used && mono_class_is_interface (cmethod->klass)) {
8807                                         /* Generic method interface
8808                                            calls are resolved via a
8809                                            helper function and don't
8810                                            need an imt. */
8811                                         if (!cmethod_context || !cmethod_context->method_inst)
8812                                                 pass_imt_from_rgctx = TRUE;
8813                                 }
8814
8815                                 /*
8816                                  * If a shared method calls another
8817                                  * shared method then the caller must
8818                                  * have a generic sharing context
8819                                  * because the magic trampoline
8820                                  * requires it.  FIXME: We shouldn't
8821                                  * have to force the vtable/mrgctx
8822                                  * variable here.  Instead there
8823                                  * should be a flag in the cfg to
8824                                  * request a generic sharing context.
8825                                  */
8826                                 if (context_used &&
8827                                                 ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
8828                                         mono_get_vtable_var (cfg);
8829                         }
8830
8831                         if (pass_vtable) {
8832                                 if (context_used) {
8833                                         vtable_arg = mini_emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
8834                                 } else {
8835                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
8836
8837                                         CHECK_TYPELOAD (cmethod->klass);
8838                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
8839                                 }
8840                         }
8841
8842                         if (pass_mrgctx) {
8843                                 g_assert (!vtable_arg);
8844
8845                                 if (!cfg->compile_aot) {
8846                                         /* 
8847                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
8848                                          * for type load errors before.
8849                                          */
8850                                         mono_class_setup_vtable (cmethod->klass);
8851                                         CHECK_TYPELOAD (cmethod->klass);
8852                                 }
8853
8854                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
8855
8856                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
8857                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
8858                                          MONO_METHOD_IS_FINAL (cmethod)) &&
8859                                         !mono_class_is_marshalbyref (cmethod->klass)) {
8860                                         if (virtual_)
8861                                                 check_this = TRUE;
8862                                         virtual_ = 0;
8863                                 }
8864                         }
8865
8866                         if (pass_imt_from_rgctx) {
8867                                 g_assert (!pass_vtable);
8868
8869                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
8870                                         cmethod, MONO_RGCTX_INFO_METHOD);
8871                         }
8872
8873                         if (check_this)
8874                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
8875
8876                         /* Calling virtual generic methods */
8877                         if (virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) &&
8878                             !(MONO_METHOD_IS_FINAL (cmethod) && 
8879                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
8880                             fsig->generic_param_count && 
8881                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) &&
8882                                 !cfg->llvm_only) {
8883                                 MonoInst *this_temp, *this_arg_temp, *store;
8884                                 MonoInst *iargs [4];
8885
8886                                 g_assert (fsig->is_inflated);
8887
8888                                 /* Prevent inlining of methods that contain indirect calls */
8889                                 INLINE_FAILURE ("virtual generic call");
8890
8891                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
8892                                         GSHAREDVT_FAILURE (*ip);
8893
8894                                 if (cfg->backend->have_generalized_imt_trampoline && cfg->backend->gshared_supported && cmethod->wrapper_type == MONO_WRAPPER_NONE) {
8895                                         g_assert (!imt_arg);
8896                                         if (!context_used)
8897                                                 g_assert (cmethod->is_inflated);
8898                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
8899                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
8900                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
8901                                 } else {
8902                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
8903                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
8904                                         MONO_ADD_INS (cfg->cbb, store);
8905
8906                                         /* FIXME: This should be a managed pointer */
8907                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8908
8909                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
8910                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
8911                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
8912                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
8913                                         addr = mono_emit_jit_icall (cfg,
8914                                                                                                 mono_helper_compile_generic_method, iargs);
8915
8916                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
8917
8918                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8919                                 }
8920
8921                                 goto call_end;
8922                         }
8923
8924                         /*
8925                          * Implement a workaround for the inherent races involved in locking:
8926                          * Monitor.Enter ()
8927                          * try {
8928                          * } finally {
8929                          *    Monitor.Exit ()
8930                          * }
8931                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
8932                          * try block, the Exit () won't be executed, see:
8933                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
8934                          * To work around this, we extend such try blocks to include the last x bytes
8935                          * of the Monitor.Enter () call.
8936                          */
8937                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
8938                                 MonoBasicBlock *tbb;
8939
8940                                 GET_BBLOCK (cfg, tbb, ip + 5);
8941                                 /* 
8942                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
8943                                  * from Monitor.Enter like ArgumentNullException.
8944                                  */
8945                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
8946                                         /* Mark this bblock as needing to be extended */
8947                                         tbb->extend_try_block = TRUE;
8948                                 }
8949                         }
8950
8951                         /* Conversion to a JIT intrinsic */
8952                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
8953                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8954                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
8955                                         emit_widen = FALSE;
8956                                 }
8957                                 goto call_end;
8958                         }
8959                         CHECK_CFG_ERROR;
8960                         
8961                         /* Inlining */
8962                         if ((cfg->opt & MONO_OPT_INLINE) &&
8963                                 (!virtual_ || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
8964                             mono_method_check_inlining (cfg, cmethod)) {
8965                                 int costs;
8966                                 gboolean always = FALSE;
8967
8968                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
8969                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
8970                                         /* Prevent inlining of methods that call wrappers */
8971                                         INLINE_FAILURE ("wrapper call");
8972                                         cmethod = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
8973                                         always = TRUE;
8974                                 }
8975
8976                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, always);
8977                                 if (costs) {
8978                                         cfg->real_offset += 5;
8979
8980                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8981                                                 /* *sp is already set by inline_method */
8982                                                 sp++;
8983                                                 push_res = FALSE;
8984                                         }
8985
8986                                         inline_costs += costs;
8987
8988                                         goto call_end;
8989                                 }
8990                         }
8991
8992                         /* Tail recursion elimination */
8993                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
8994                                 gboolean has_vtargs = FALSE;
8995                                 int i;
8996
8997                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
8998                                 INLINE_FAILURE ("tail call");
8999
9000                                 /* keep it simple */
9001                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
9002                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
9003                                                 has_vtargs = TRUE;
9004                                 }
9005
9006                                 if (!has_vtargs) {
9007                                         if (need_seq_point) {
9008                                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
9009                                                 need_seq_point = FALSE;
9010                                         }
9011                                         for (i = 0; i < n; ++i)
9012                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9013                                         MONO_INST_NEW (cfg, ins, OP_BR);
9014                                         MONO_ADD_INS (cfg->cbb, ins);
9015                                         tblock = start_bblock->out_bb [0];
9016                                         link_bblock (cfg, cfg->cbb, tblock);
9017                                         ins->inst_target_bb = tblock;
9018                                         start_new_bblock = 1;
9019
9020                                         /* skip the CEE_RET, too */
9021                                         if (ip_in_bb (cfg, cfg->cbb, ip + 5))
9022                                                 skip_ret = TRUE;
9023                                         push_res = FALSE;
9024                                         goto call_end;
9025                                 }
9026                         }
9027
9028                         inline_costs += 10 * num_calls++;
9029
9030                         /*
9031                          * Synchronized wrappers.
9032                          * Its hard to determine where to replace a method with its synchronized
9033                          * wrapper without causing an infinite recursion. The current solution is
9034                          * to add the synchronized wrapper in the trampolines, and to
9035                          * change the called method to a dummy wrapper, and resolve that wrapper
9036                          * to the real method in mono_jit_compile_method ().
9037                          */
9038                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
9039                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
9040                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
9041                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
9042                         }
9043
9044                         /*
9045                          * Making generic calls out of gsharedvt methods.
9046                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9047                          * patching gshared method addresses into a gsharedvt method.
9048                          */
9049                         if (cfg->gsharedvt && (mini_is_gsharedvt_signature (fsig) || cmethod->is_inflated || mono_class_is_ginst (cmethod->klass)) &&
9050                                 !(cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY) &&
9051                                 (!(cfg->llvm_only && virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)))) {
9052                                 MonoRgctxInfoType info_type;
9053
9054                                 if (virtual_) {
9055                                         //if (mono_class_is_interface (cmethod->klass))
9056                                                 //GSHAREDVT_FAILURE (*ip);
9057                                         // disable for possible remoting calls
9058                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
9059                                                 GSHAREDVT_FAILURE (*ip);
9060                                         if (fsig->generic_param_count) {
9061                                                 /* virtual generic call */
9062                                                 g_assert (!imt_arg);
9063                                                 /* Same as the virtual generic case above */
9064                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9065                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9066                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
9067                                                 vtable_arg = NULL;
9068                                         } else if (mono_class_is_interface (cmethod->klass) && !imt_arg) {
9069                                                 /* This can happen when we call a fully instantiated iface method */
9070                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9071                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9072                                                 vtable_arg = NULL;
9073                                         }
9074                                 }
9075
9076                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
9077                                         keep_this_alive = sp [0];
9078
9079                                 if (virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
9080                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
9081                                 else
9082                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
9083                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
9084
9085                                 if (cfg->llvm_only) {
9086                                         // FIXME: Avoid initializing vtable_arg
9087                                         ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
9088                                 } else {
9089                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9090                                 }
9091                                 goto call_end;
9092                         }
9093
9094                         /* Generic sharing */
9095
9096                         /*
9097                          * Use this if the callee is gsharedvt sharable too, since
9098                          * at runtime we might find an instantiation so the call cannot
9099                          * be patched (the 'no_patch' code path in mini-trampolines.c).
9100                          */
9101                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
9102                                 (!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
9103                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
9104                                 (!virtual_ || MONO_METHOD_IS_FINAL (cmethod) ||
9105                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
9106                                 INLINE_FAILURE ("gshared");
9107
9108                                 g_assert (cfg->gshared && cmethod);
9109                                 g_assert (!addr);
9110
9111                                 /*
9112                                  * We are compiling a call to a
9113                                  * generic method from shared code,
9114                                  * which means that we have to look up
9115                                  * the method in the rgctx and do an
9116                                  * indirect call.
9117                                  */
9118                                 if (fsig->hasthis)
9119                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9120
9121                                 if (cfg->llvm_only) {
9122                                         if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig))
9123                                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER);
9124                                         else
9125                                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9126                                         // FIXME: Avoid initializing imt_arg/vtable_arg
9127                                         ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
9128                                 } else {
9129                                         addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9130                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9131                                 }
9132                                 goto call_end;
9133                         }
9134
9135                         /* Direct calls to icalls */
9136                         if (direct_icall) {
9137                                 MonoMethod *wrapper;
9138                                 int costs;
9139
9140                                 /* Inline the wrapper */
9141                                 wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9142
9143                                 costs = inline_method (cfg, wrapper, fsig, sp, ip, cfg->real_offset, TRUE);
9144                                 g_assert (costs > 0);
9145                                 cfg->real_offset += 5;
9146
9147                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9148                                         /* *sp is already set by inline_method */
9149                                         sp++;
9150                                         push_res = FALSE;
9151                                 }
9152
9153                                 inline_costs += costs;
9154
9155                                 goto call_end;
9156                         }
9157                                         
9158                         /* Array methods */
9159                         if (array_rank) {
9160                                 MonoInst *addr;
9161
9162                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
9163                                         MonoInst *val = sp [fsig->param_count];
9164
9165                                         if (val->type == STACK_OBJ) {
9166                                                 MonoInst *iargs [2];
9167
9168                                                 iargs [0] = sp [0];
9169                                                 iargs [1] = val;
9170                                                 
9171                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
9172                                         }
9173                                         
9174                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
9175                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
9176                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !MONO_INS_IS_PCONST_NULL (val))
9177                                                 emit_write_barrier (cfg, addr, val);
9178                                         if (cfg->gen_write_barriers && mini_is_gsharedvt_klass (cmethod->klass))
9179                                                 GSHAREDVT_FAILURE (*ip);
9180                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
9181                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9182
9183                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
9184                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
9185                                         if (!cmethod->klass->element_class->valuetype && !readonly)
9186                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
9187                                         CHECK_TYPELOAD (cmethod->klass);
9188                                         
9189                                         readonly = FALSE;
9190                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9191                                         ins = addr;
9192                                 } else {
9193                                         g_assert_not_reached ();
9194                                 }
9195
9196                                 emit_widen = FALSE;
9197                                 goto call_end;
9198                         }
9199
9200                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual_ ? sp [0] : NULL);
9201                         if (ins)
9202                                 goto call_end;
9203
9204                         /* Tail prefix / tail call optimization */
9205
9206                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
9207                         /* FIXME: runtime generic context pointer for jumps? */
9208                         /* FIXME: handle this for generic sharing eventually */
9209                         if ((ins_flag & MONO_INST_TAILCALL) &&
9210                                 !vtable_arg && !cfg->gshared && is_supported_tail_call (cfg, method, cmethod, fsig, call_opcode))
9211                                 supported_tail_call = TRUE;
9212
9213                         if (supported_tail_call) {
9214                                 MonoCallInst *call;
9215
9216                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9217                                 INLINE_FAILURE ("tail call");
9218
9219                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
9220
9221                                 if (cfg->backend->have_op_tail_call) {
9222                                         /* Handle tail calls similarly to normal calls */
9223                                         tail_call = TRUE;
9224                                 } else {
9225                                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9226
9227                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9228                                         call->tail_call = TRUE;
9229                                         call->method = cmethod;
9230                                         call->signature = mono_method_signature (cmethod);
9231
9232                                         /*
9233                                          * We implement tail calls by storing the actual arguments into the 
9234                                          * argument variables, then emitting a CEE_JMP.
9235                                          */
9236                                         for (i = 0; i < n; ++i) {
9237                                                 /* Prevent argument from being register allocated */
9238                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
9239                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9240                                         }
9241                                         ins = (MonoInst*)call;
9242                                         ins->inst_p0 = cmethod;
9243                                         ins->inst_p1 = arg_array [0];
9244                                         MONO_ADD_INS (cfg->cbb, ins);
9245                                         link_bblock (cfg, cfg->cbb, end_bblock);
9246                                         start_new_bblock = 1;
9247
9248                                         // FIXME: Eliminate unreachable epilogs
9249
9250                                         /*
9251                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9252                                          * only reachable from this call.
9253                                          */
9254                                         GET_BBLOCK (cfg, tblock, ip + 5);
9255                                         if (tblock == cfg->cbb || tblock->in_count == 0)
9256                                                 skip_ret = TRUE;
9257                                         push_res = FALSE;
9258
9259                                         goto call_end;
9260                                 }
9261                         }
9262
9263                         /*
9264                          * Virtual calls in llvm-only mode.
9265                          */
9266                         if (cfg->llvm_only && virtual_ && cmethod && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
9267                                 ins = emit_llvmonly_virtual_call (cfg, cmethod, fsig, context_used, sp);
9268                                 goto call_end;
9269                         }
9270
9271                         /* Common call */
9272                         if (!(cmethod->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
9273                                 INLINE_FAILURE ("call");
9274                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual_ ? sp [0] : NULL,
9275                                                                                           imt_arg, vtable_arg);
9276
9277                         if (tail_call && !cfg->llvm_only) {
9278                                 link_bblock (cfg, cfg->cbb, end_bblock);
9279                                 start_new_bblock = 1;
9280
9281                                 // FIXME: Eliminate unreachable epilogs
9282
9283                                 /*
9284                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9285                                  * only reachable from this call.
9286                                  */
9287                                 GET_BBLOCK (cfg, tblock, ip + 5);
9288                                 if (tblock == cfg->cbb || tblock->in_count == 0)
9289                                         skip_ret = TRUE;
9290                                 push_res = FALSE;
9291                         }
9292
9293                         call_end:
9294
9295                         /* End of call, INS should contain the result of the call, if any */
9296
9297                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
9298                                 g_assert (ins);
9299                                 if (emit_widen)
9300                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
9301                                 else
9302                                         *sp++ = ins;
9303                         }
9304
9305                         if (keep_this_alive) {
9306                                 MonoInst *dummy_use;
9307
9308                                 /* See mono_emit_method_call_full () */
9309                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
9310                         }
9311
9312                         if (cfg->llvm_only && cmethod && method_needs_stack_walk (cfg, cmethod)) {
9313                                 /*
9314                                  * Clang can convert these calls to tail calls which screw up the stack
9315                                  * walk. This happens even when the -fno-optimize-sibling-calls
9316                                  * option is passed to clang.
9317                                  * Work around this by emitting a dummy call.
9318                                  */
9319                                 mono_emit_jit_icall (cfg, mono_dummy_jit_icall, NULL);
9320                         }
9321
9322                         CHECK_CFG_EXCEPTION;
9323
9324                         ip += 5;
9325                         if (skip_ret) {
9326                                 g_assert (*ip == CEE_RET);
9327                                 ip += 1;
9328                         }
9329                         ins_flag = 0;
9330                         constrained_class = NULL;
9331                         if (need_seq_point)
9332                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
9333                         break;
9334                 }
9335                 case CEE_RET:
9336                         if (cfg->method != method) {
9337                                 /* return from inlined method */
9338                                 /* 
9339                                  * If in_count == 0, that means the ret is unreachable due to
9340                                  * being preceeded by a throw. In that case, inline_method () will
9341                                  * handle setting the return value 
9342                                  * (test case: test_0_inline_throw ()).
9343                                  */
9344                                 if (return_var && cfg->cbb->in_count) {
9345                                         MonoType *ret_type = mono_method_signature (method)->ret;
9346
9347                                         MonoInst *store;
9348                                         CHECK_STACK (1);
9349                                         --sp;
9350
9351                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9352                                                 UNVERIFIED;
9353
9354                                         //g_assert (returnvar != -1);
9355                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
9356                                         cfg->ret_var_set = TRUE;
9357                                 } 
9358                         } else {
9359                                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
9360
9361                                 if (cfg->lmf_var && cfg->cbb->in_count && !cfg->llvm_only)
9362                                         emit_pop_lmf (cfg);
9363
9364                                 if (cfg->ret) {
9365                                         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (method)->ret);
9366
9367                                         if (seq_points && !sym_seq_points) {
9368                                                 /* 
9369                                                  * Place a seq point here too even through the IL stack is not
9370                                                  * empty, so a step over on
9371                                                  * call <FOO>
9372                                                  * ret
9373                                                  * will work correctly.
9374                                                  */
9375                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
9376                                                 MONO_ADD_INS (cfg->cbb, ins);
9377                                         }
9378
9379                                         g_assert (!return_var);
9380                                         CHECK_STACK (1);
9381                                         --sp;
9382
9383                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9384                                                 UNVERIFIED;
9385
9386                                         emit_setret (cfg, *sp);
9387                                 }
9388                         }
9389                         if (sp != stack_start)
9390                                 UNVERIFIED;
9391                         MONO_INST_NEW (cfg, ins, OP_BR);
9392                         ip++;
9393                         ins->inst_target_bb = end_bblock;
9394                         MONO_ADD_INS (cfg->cbb, ins);
9395                         link_bblock (cfg, cfg->cbb, end_bblock);
9396                         start_new_bblock = 1;
9397                         break;
9398                 case CEE_BR_S:
9399                         CHECK_OPSIZE (2);
9400                         MONO_INST_NEW (cfg, ins, OP_BR);
9401                         ip++;
9402                         target = ip + 1 + (signed char)(*ip);
9403                         ++ip;
9404                         GET_BBLOCK (cfg, tblock, target);
9405                         link_bblock (cfg, cfg->cbb, tblock);
9406                         ins->inst_target_bb = tblock;
9407                         if (sp != stack_start) {
9408                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9409                                 sp = stack_start;
9410                                 CHECK_UNVERIFIABLE (cfg);
9411                         }
9412                         MONO_ADD_INS (cfg->cbb, ins);
9413                         start_new_bblock = 1;
9414                         inline_costs += BRANCH_COST;
9415                         break;
9416                 case CEE_BEQ_S:
9417                 case CEE_BGE_S:
9418                 case CEE_BGT_S:
9419                 case CEE_BLE_S:
9420                 case CEE_BLT_S:
9421                 case CEE_BNE_UN_S:
9422                 case CEE_BGE_UN_S:
9423                 case CEE_BGT_UN_S:
9424                 case CEE_BLE_UN_S:
9425                 case CEE_BLT_UN_S:
9426                         CHECK_OPSIZE (2);
9427                         CHECK_STACK (2);
9428                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
9429                         ip++;
9430                         target = ip + 1 + *(signed char*)ip;
9431                         ip++;
9432
9433                         ADD_BINCOND (NULL);
9434
9435                         sp = stack_start;
9436                         inline_costs += BRANCH_COST;
9437                         break;
9438                 case CEE_BR:
9439                         CHECK_OPSIZE (5);
9440                         MONO_INST_NEW (cfg, ins, OP_BR);
9441                         ip++;
9442
9443                         target = ip + 4 + (gint32)read32(ip);
9444                         ip += 4;
9445                         GET_BBLOCK (cfg, tblock, target);
9446                         link_bblock (cfg, cfg->cbb, tblock);
9447                         ins->inst_target_bb = tblock;
9448                         if (sp != stack_start) {
9449                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9450                                 sp = stack_start;
9451                                 CHECK_UNVERIFIABLE (cfg);
9452                         }
9453
9454                         MONO_ADD_INS (cfg->cbb, ins);
9455
9456                         start_new_bblock = 1;
9457                         inline_costs += BRANCH_COST;
9458                         break;
9459                 case CEE_BRFALSE_S:
9460                 case CEE_BRTRUE_S:
9461                 case CEE_BRFALSE:
9462                 case CEE_BRTRUE: {
9463                         MonoInst *cmp;
9464                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
9465                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
9466                         guint32 opsize = is_short ? 1 : 4;
9467
9468                         CHECK_OPSIZE (opsize);
9469                         CHECK_STACK (1);
9470                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
9471                                 UNVERIFIED;
9472                         ip ++;
9473                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
9474                         ip += opsize;
9475
9476                         sp--;
9477
9478                         GET_BBLOCK (cfg, tblock, target);
9479                         link_bblock (cfg, cfg->cbb, tblock);
9480                         GET_BBLOCK (cfg, tblock, ip);
9481                         link_bblock (cfg, cfg->cbb, tblock);
9482
9483                         if (sp != stack_start) {
9484                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9485                                 CHECK_UNVERIFIABLE (cfg);
9486                         }
9487
9488                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
9489                         cmp->sreg1 = sp [0]->dreg;
9490                         type_from_op (cfg, cmp, sp [0], NULL);
9491                         CHECK_TYPE (cmp);
9492
9493 #if SIZEOF_REGISTER == 4
9494                         if (cmp->opcode == OP_LCOMPARE_IMM) {
9495                                 /* Convert it to OP_LCOMPARE */
9496                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
9497                                 ins->type = STACK_I8;
9498                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
9499                                 ins->inst_l = 0;
9500                                 MONO_ADD_INS (cfg->cbb, ins);
9501                                 cmp->opcode = OP_LCOMPARE;
9502                                 cmp->sreg2 = ins->dreg;
9503                         }
9504 #endif
9505                         MONO_ADD_INS (cfg->cbb, cmp);
9506
9507                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
9508                         type_from_op (cfg, ins, sp [0], NULL);
9509                         MONO_ADD_INS (cfg->cbb, ins);
9510                         ins->inst_many_bb = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
9511                         GET_BBLOCK (cfg, tblock, target);
9512                         ins->inst_true_bb = tblock;
9513                         GET_BBLOCK (cfg, tblock, ip);
9514                         ins->inst_false_bb = tblock;
9515                         start_new_bblock = 2;
9516
9517                         sp = stack_start;
9518                         inline_costs += BRANCH_COST;
9519                         break;
9520                 }
9521                 case CEE_BEQ:
9522                 case CEE_BGE:
9523                 case CEE_BGT:
9524                 case CEE_BLE:
9525                 case CEE_BLT:
9526                 case CEE_BNE_UN:
9527                 case CEE_BGE_UN:
9528                 case CEE_BGT_UN:
9529                 case CEE_BLE_UN:
9530                 case CEE_BLT_UN:
9531                         CHECK_OPSIZE (5);
9532                         CHECK_STACK (2);
9533                         MONO_INST_NEW (cfg, ins, *ip);
9534                         ip++;
9535                         target = ip + 4 + (gint32)read32(ip);
9536                         ip += 4;
9537
9538                         ADD_BINCOND (NULL);
9539
9540                         sp = stack_start;
9541                         inline_costs += BRANCH_COST;
9542                         break;
9543                 case CEE_SWITCH: {
9544                         MonoInst *src1;
9545                         MonoBasicBlock **targets;
9546                         MonoBasicBlock *default_bblock;
9547                         MonoJumpInfoBBTable *table;
9548                         int offset_reg = alloc_preg (cfg);
9549                         int target_reg = alloc_preg (cfg);
9550                         int table_reg = alloc_preg (cfg);
9551                         int sum_reg = alloc_preg (cfg);
9552                         gboolean use_op_switch;
9553
9554                         CHECK_OPSIZE (5);
9555                         CHECK_STACK (1);
9556                         n = read32 (ip + 1);
9557                         --sp;
9558                         src1 = sp [0];
9559                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
9560                                 UNVERIFIED;
9561
9562                         ip += 5;
9563                         CHECK_OPSIZE (n * sizeof (guint32));
9564                         target = ip + n * sizeof (guint32);
9565
9566                         GET_BBLOCK (cfg, default_bblock, target);
9567                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
9568
9569                         targets = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
9570                         for (i = 0; i < n; ++i) {
9571                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
9572                                 targets [i] = tblock;
9573                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
9574                                 ip += 4;
9575                         }
9576
9577                         if (sp != stack_start) {
9578                                 /* 
9579                                  * Link the current bb with the targets as well, so handle_stack_args
9580                                  * will set their in_stack correctly.
9581                                  */
9582                                 link_bblock (cfg, cfg->cbb, default_bblock);
9583                                 for (i = 0; i < n; ++i)
9584                                         link_bblock (cfg, cfg->cbb, targets [i]);
9585
9586                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9587                                 sp = stack_start;
9588                                 CHECK_UNVERIFIABLE (cfg);
9589
9590                                 /* Undo the links */
9591                                 mono_unlink_bblock (cfg, cfg->cbb, default_bblock);
9592                                 for (i = 0; i < n; ++i)
9593                                         mono_unlink_bblock (cfg, cfg->cbb, targets [i]);
9594                         }
9595
9596                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
9597                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
9598
9599                         for (i = 0; i < n; ++i)
9600                                 link_bblock (cfg, cfg->cbb, targets [i]);
9601
9602                         table = (MonoJumpInfoBBTable *)mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
9603                         table->table = targets;
9604                         table->table_size = n;
9605
9606                         use_op_switch = FALSE;
9607 #ifdef TARGET_ARM
9608                         /* ARM implements SWITCH statements differently */
9609                         /* FIXME: Make it use the generic implementation */
9610                         if (!cfg->compile_aot)
9611                                 use_op_switch = TRUE;
9612 #endif
9613
9614                         if (COMPILE_LLVM (cfg))
9615                                 use_op_switch = TRUE;
9616
9617                         cfg->cbb->has_jump_table = 1;
9618
9619                         if (use_op_switch) {
9620                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
9621                                 ins->sreg1 = src1->dreg;
9622                                 ins->inst_p0 = table;
9623                                 ins->inst_many_bb = targets;
9624                                 ins->klass = (MonoClass *)GUINT_TO_POINTER (n);
9625                                 MONO_ADD_INS (cfg->cbb, ins);
9626                         } else {
9627                                 if (sizeof (gpointer) == 8)
9628                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
9629                                 else
9630                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
9631
9632 #if SIZEOF_REGISTER == 8
9633                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
9634                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
9635 #endif
9636
9637                                 if (cfg->compile_aot) {
9638                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
9639                                 } else {
9640                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
9641                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
9642                                         ins->inst_p0 = table;
9643                                         ins->dreg = table_reg;
9644                                         MONO_ADD_INS (cfg->cbb, ins);
9645                                 }
9646
9647                                 /* FIXME: Use load_memindex */
9648                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
9649                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
9650                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
9651                         }
9652                         start_new_bblock = 1;
9653                         inline_costs += (BRANCH_COST * 2);
9654                         break;
9655                 }
9656                 case CEE_LDIND_I1:
9657                 case CEE_LDIND_U1:
9658                 case CEE_LDIND_I2:
9659                 case CEE_LDIND_U2:
9660                 case CEE_LDIND_I4:
9661                 case CEE_LDIND_U4:
9662                 case CEE_LDIND_I8:
9663                 case CEE_LDIND_I:
9664                 case CEE_LDIND_R4:
9665                 case CEE_LDIND_R8:
9666                 case CEE_LDIND_REF:
9667                         CHECK_STACK (1);
9668                         --sp;
9669
9670                         switch (*ip) {
9671                         case CEE_LDIND_R4:
9672                         case CEE_LDIND_R8:
9673                                 dreg = alloc_freg (cfg);
9674                                 break;
9675                         case CEE_LDIND_I8:
9676                                 dreg = alloc_lreg (cfg);
9677                                 break;
9678                         case CEE_LDIND_REF:
9679                                 dreg = alloc_ireg_ref (cfg);
9680                                 break;
9681                         default:
9682                                 dreg = alloc_preg (cfg);
9683                         }
9684
9685                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
9686                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
9687                         if (*ip == CEE_LDIND_R4)
9688                                 ins->type = cfg->r4_stack_type;
9689                         ins->flags |= ins_flag;
9690                         MONO_ADD_INS (cfg->cbb, ins);
9691                         *sp++ = ins;
9692                         if (ins_flag & MONO_INST_VOLATILE) {
9693                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
9694                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
9695                         }
9696                         ins_flag = 0;
9697                         ++ip;
9698                         break;
9699                 case CEE_STIND_REF:
9700                 case CEE_STIND_I1:
9701                 case CEE_STIND_I2:
9702                 case CEE_STIND_I4:
9703                 case CEE_STIND_I8:
9704                 case CEE_STIND_R4:
9705                 case CEE_STIND_R8:
9706                 case CEE_STIND_I:
9707                         CHECK_STACK (2);
9708                         sp -= 2;
9709
9710                         if (ins_flag & MONO_INST_VOLATILE) {
9711                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
9712                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
9713                         }
9714
9715                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
9716                         ins->flags |= ins_flag;
9717                         ins_flag = 0;
9718
9719                         MONO_ADD_INS (cfg->cbb, ins);
9720
9721                         if (cfg->gen_write_barriers && *ip == CEE_STIND_REF && method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER && !MONO_INS_IS_PCONST_NULL (sp [1]))
9722                                 emit_write_barrier (cfg, sp [0], sp [1]);
9723
9724                         inline_costs += 1;
9725                         ++ip;
9726                         break;
9727
9728                 case CEE_MUL:
9729                         CHECK_STACK (2);
9730
9731                         MONO_INST_NEW (cfg, ins, (*ip));
9732                         sp -= 2;
9733                         ins->sreg1 = sp [0]->dreg;
9734                         ins->sreg2 = sp [1]->dreg;
9735                         type_from_op (cfg, ins, sp [0], sp [1]);
9736                         CHECK_TYPE (ins);
9737                         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type);
9738
9739                         /* Use the immediate opcodes if possible */
9740                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
9741                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
9742                                 if (imm_opcode != -1) {
9743                                         ins->opcode = imm_opcode;
9744                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
9745                                         ins->sreg2 = -1;
9746
9747                                         NULLIFY_INS (sp [1]);
9748                                 }
9749                         }
9750
9751                         MONO_ADD_INS ((cfg)->cbb, (ins));
9752
9753                         *sp++ = mono_decompose_opcode (cfg, ins);
9754                         ip++;
9755                         break;
9756                 case CEE_ADD:
9757                 case CEE_SUB:
9758                 case CEE_DIV:
9759                 case CEE_DIV_UN:
9760                 case CEE_REM:
9761                 case CEE_REM_UN:
9762                 case CEE_AND:
9763                 case CEE_OR:
9764                 case CEE_XOR:
9765                 case CEE_SHL:
9766                 case CEE_SHR:
9767                 case CEE_SHR_UN:
9768                         CHECK_STACK (2);
9769
9770                         MONO_INST_NEW (cfg, ins, (*ip));
9771                         sp -= 2;
9772                         ins->sreg1 = sp [0]->dreg;
9773                         ins->sreg2 = sp [1]->dreg;
9774                         type_from_op (cfg, ins, sp [0], sp [1]);
9775                         CHECK_TYPE (ins);
9776                         add_widen_op (cfg, ins, &sp [0], &sp [1]);
9777                         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type);
9778
9779                         /* FIXME: Pass opcode to is_inst_imm */
9780
9781                         /* Use the immediate opcodes if possible */
9782                         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)) {
9783                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
9784                                 if (imm_opcode != -1) {
9785                                         ins->opcode = imm_opcode;
9786                                         if (sp [1]->opcode == OP_I8CONST) {
9787 #if SIZEOF_REGISTER == 8
9788                                                 ins->inst_imm = sp [1]->inst_l;
9789 #else
9790                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
9791                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
9792 #endif
9793                                         }
9794                                         else
9795                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
9796                                         ins->sreg2 = -1;
9797
9798                                         /* Might be followed by an instruction added by add_widen_op */
9799                                         if (sp [1]->next == NULL)
9800                                                 NULLIFY_INS (sp [1]);
9801                                 }
9802                         }
9803                         MONO_ADD_INS ((cfg)->cbb, (ins));
9804
9805                         *sp++ = mono_decompose_opcode (cfg, ins);
9806                         ip++;
9807                         break;
9808                 case CEE_NEG:
9809                 case CEE_NOT:
9810                 case CEE_CONV_I1:
9811                 case CEE_CONV_I2:
9812                 case CEE_CONV_I4:
9813                 case CEE_CONV_R4:
9814                 case CEE_CONV_R8:
9815                 case CEE_CONV_U4:
9816                 case CEE_CONV_I8:
9817                 case CEE_CONV_U8:
9818                 case CEE_CONV_OVF_I8:
9819                 case CEE_CONV_OVF_U8:
9820                 case CEE_CONV_R_UN:
9821                         CHECK_STACK (1);
9822
9823                         /* Special case this earlier so we have long constants in the IR */
9824                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
9825                                 int data = sp [-1]->inst_c0;
9826                                 sp [-1]->opcode = OP_I8CONST;
9827                                 sp [-1]->type = STACK_I8;
9828 #if SIZEOF_REGISTER == 8
9829                                 if ((*ip) == CEE_CONV_U8)
9830                                         sp [-1]->inst_c0 = (guint32)data;
9831                                 else
9832                                         sp [-1]->inst_c0 = data;
9833 #else
9834                                 sp [-1]->inst_ls_word = data;
9835                                 if ((*ip) == CEE_CONV_U8)
9836                                         sp [-1]->inst_ms_word = 0;
9837                                 else
9838                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
9839 #endif
9840                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
9841                         }
9842                         else {
9843                                 ADD_UNOP (*ip);
9844                         }
9845                         ip++;
9846                         break;
9847                 case CEE_CONV_OVF_I4:
9848                 case CEE_CONV_OVF_I1:
9849                 case CEE_CONV_OVF_I2:
9850                 case CEE_CONV_OVF_I:
9851                 case CEE_CONV_OVF_U:
9852                         CHECK_STACK (1);
9853
9854                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
9855                                 ADD_UNOP (CEE_CONV_OVF_I8);
9856                                 ADD_UNOP (*ip);
9857                         } else {
9858                                 ADD_UNOP (*ip);
9859                         }
9860                         ip++;
9861                         break;
9862                 case CEE_CONV_OVF_U1:
9863                 case CEE_CONV_OVF_U2:
9864                 case CEE_CONV_OVF_U4:
9865                         CHECK_STACK (1);
9866
9867                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
9868                                 ADD_UNOP (CEE_CONV_OVF_U8);
9869                                 ADD_UNOP (*ip);
9870                         } else {
9871                                 ADD_UNOP (*ip);
9872                         }
9873                         ip++;
9874                         break;
9875                 case CEE_CONV_OVF_I1_UN:
9876                 case CEE_CONV_OVF_I2_UN:
9877                 case CEE_CONV_OVF_I4_UN:
9878                 case CEE_CONV_OVF_I8_UN:
9879                 case CEE_CONV_OVF_U1_UN:
9880                 case CEE_CONV_OVF_U2_UN:
9881                 case CEE_CONV_OVF_U4_UN:
9882                 case CEE_CONV_OVF_U8_UN:
9883                 case CEE_CONV_OVF_I_UN:
9884                 case CEE_CONV_OVF_U_UN:
9885                 case CEE_CONV_U2:
9886                 case CEE_CONV_U1:
9887                 case CEE_CONV_I:
9888                 case CEE_CONV_U:
9889                         CHECK_STACK (1);
9890                         ADD_UNOP (*ip);
9891                         CHECK_CFG_EXCEPTION;
9892                         ip++;
9893                         break;
9894                 case CEE_ADD_OVF:
9895                 case CEE_ADD_OVF_UN:
9896                 case CEE_MUL_OVF:
9897                 case CEE_MUL_OVF_UN:
9898                 case CEE_SUB_OVF:
9899                 case CEE_SUB_OVF_UN:
9900                         CHECK_STACK (2);
9901                         ADD_BINOP (*ip);
9902                         ip++;
9903                         break;
9904                 case CEE_CPOBJ:
9905                         GSHAREDVT_FAILURE (*ip);
9906                         CHECK_OPSIZE (5);
9907                         CHECK_STACK (2);
9908                         token = read32 (ip + 1);
9909                         klass = mini_get_class (method, token, generic_context);
9910                         CHECK_TYPELOAD (klass);
9911                         sp -= 2;
9912                         if (generic_class_is_reference_type (cfg, klass)) {
9913                                 MonoInst *store, *load;
9914                                 int dreg = alloc_ireg_ref (cfg);
9915
9916                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
9917                                 load->flags |= ins_flag;
9918                                 MONO_ADD_INS (cfg->cbb, load);
9919
9920                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
9921                                 store->flags |= ins_flag;
9922                                 MONO_ADD_INS (cfg->cbb, store);
9923
9924                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
9925                                         emit_write_barrier (cfg, sp [0], sp [1]);
9926                         } else {
9927                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
9928                         }
9929                         ins_flag = 0;
9930                         ip += 5;
9931                         break;
9932                 case CEE_LDOBJ: {
9933                         int loc_index = -1;
9934                         int stloc_len = 0;
9935
9936                         CHECK_OPSIZE (5);
9937                         CHECK_STACK (1);
9938                         --sp;
9939                         token = read32 (ip + 1);
9940                         klass = mini_get_class (method, token, generic_context);
9941                         CHECK_TYPELOAD (klass);
9942
9943                         /* Optimize the common ldobj+stloc combination */
9944                         switch (ip [5]) {
9945                         case CEE_STLOC_S:
9946                                 loc_index = ip [6];
9947                                 stloc_len = 2;
9948                                 break;
9949                         case CEE_STLOC_0:
9950                         case CEE_STLOC_1:
9951                         case CEE_STLOC_2:
9952                         case CEE_STLOC_3:
9953                                 loc_index = ip [5] - CEE_STLOC_0;
9954                                 stloc_len = 1;
9955                                 break;
9956                         default:
9957                                 break;
9958                         }
9959
9960                         if ((loc_index != -1) && ip_in_bb (cfg, cfg->cbb, ip + 5)) {
9961                                 CHECK_LOCAL (loc_index);
9962
9963                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
9964                                 ins->dreg = cfg->locals [loc_index]->dreg;
9965                                 ins->flags |= ins_flag;
9966                                 ip += 5;
9967                                 ip += stloc_len;
9968                                 if (ins_flag & MONO_INST_VOLATILE) {
9969                                         /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
9970                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
9971                                 }
9972                                 ins_flag = 0;
9973                                 break;
9974                         }
9975
9976                         /* Optimize the ldobj+stobj combination */
9977                         /* The reference case ends up being a load+store anyway */
9978                         /* Skip this if the operation is volatile. */
9979                         if (((ip [5] == CEE_STOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 5) && read32 (ip + 6) == token) && !generic_class_is_reference_type (cfg, klass) && !(ins_flag & MONO_INST_VOLATILE)) {
9980                                 CHECK_STACK (1);
9981
9982                                 sp --;
9983
9984                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
9985
9986                                 ip += 5 + 5;
9987                                 ins_flag = 0;
9988                                 break;
9989                         }
9990
9991                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
9992                         ins->flags |= ins_flag;
9993                         *sp++ = ins;
9994
9995                         if (ins_flag & MONO_INST_VOLATILE) {
9996                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
9997                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
9998                         }
9999
10000                         ip += 5;
10001                         ins_flag = 0;
10002                         inline_costs += 1;
10003                         break;
10004                 }
10005                 case CEE_LDSTR:
10006                         CHECK_STACK_OVF (1);
10007                         CHECK_OPSIZE (5);
10008                         n = read32 (ip + 1);
10009
10010                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
10011                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
10012                                 ins->type = STACK_OBJ;
10013                                 *sp = ins;
10014                         }
10015                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
10016                                 MonoInst *iargs [1];
10017                                 char *str = (char *)mono_method_get_wrapper_data (method, n);
10018
10019                                 if (cfg->compile_aot)
10020                                         EMIT_NEW_LDSTRLITCONST (cfg, iargs [0], str);
10021                                 else
10022                                         EMIT_NEW_PCONST (cfg, iargs [0], str);
10023                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
10024                         } else {
10025                                 if (cfg->opt & MONO_OPT_SHARED) {
10026                                         MonoInst *iargs [3];
10027
10028                                         if (cfg->compile_aot) {
10029                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
10030                                         }
10031                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10032                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
10033                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
10034                                         *sp = mono_emit_jit_icall (cfg, ves_icall_mono_ldstr, iargs);
10035                                         mono_ldstr_checked (cfg->domain, image, mono_metadata_token_index (n), &cfg->error);
10036                                         CHECK_CFG_ERROR;
10037                                 } else {
10038                                         if (cfg->cbb->out_of_line) {
10039                                                 MonoInst *iargs [2];
10040
10041                                                 if (image == mono_defaults.corlib) {
10042                                                         /* 
10043                                                          * Avoid relocations in AOT and save some space by using a 
10044                                                          * version of helper_ldstr specialized to mscorlib.
10045                                                          */
10046                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
10047                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
10048                                                 } else {
10049                                                         /* Avoid creating the string object */
10050                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
10051                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
10052                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
10053                                                 }
10054                                         } 
10055                                         else
10056                                         if (cfg->compile_aot) {
10057                                                 NEW_LDSTRCONST (cfg, ins, image, n);
10058                                                 *sp = ins;
10059                                                 MONO_ADD_INS (cfg->cbb, ins);
10060                                         } 
10061                                         else {
10062                                                 NEW_PCONST (cfg, ins, NULL);
10063                                                 ins->type = STACK_OBJ;
10064                                                 ins->inst_p0 = mono_ldstr_checked (cfg->domain, image, mono_metadata_token_index (n), &cfg->error);
10065                                                 CHECK_CFG_ERROR;
10066                                                 
10067                                                 if (!ins->inst_p0)
10068                                                         OUT_OF_MEMORY_FAILURE;
10069
10070                                                 *sp = ins;
10071                                                 MONO_ADD_INS (cfg->cbb, ins);
10072                                         }
10073                                 }
10074                         }
10075
10076                         sp++;
10077                         ip += 5;
10078                         break;
10079                 case CEE_NEWOBJ: {
10080                         MonoInst *iargs [2];
10081                         MonoMethodSignature *fsig;
10082                         MonoInst this_ins;
10083                         MonoInst *alloc;
10084                         MonoInst *vtable_arg = NULL;
10085
10086                         CHECK_OPSIZE (5);
10087                         token = read32 (ip + 1);
10088                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
10089                         CHECK_CFG_ERROR;
10090
10091                         fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
10092                         CHECK_CFG_ERROR;
10093
10094                         mono_save_token_info (cfg, image, token, cmethod);
10095
10096                         if (!mono_class_init (cmethod->klass))
10097                                 TYPE_LOAD_ERROR (cmethod->klass);
10098
10099                         context_used = mini_method_check_context_used (cfg, cmethod);
10100
10101                         if (mono_security_core_clr_enabled ())
10102                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
10103
10104                         if (cfg->gshared && cmethod && cmethod->klass != method->klass && mono_class_is_ginst (cmethod->klass) && mono_method_is_generic_sharable (cmethod, TRUE) && mono_class_needs_cctor_run (cmethod->klass, method)) {
10105                                 emit_class_init (cfg, cmethod->klass);
10106                                 CHECK_TYPELOAD (cmethod->klass);
10107                         }
10108
10109                         /*
10110                         if (cfg->gsharedvt) {
10111                                 if (mini_is_gsharedvt_variable_signature (sig))
10112                                         GSHAREDVT_FAILURE (*ip);
10113                         }
10114                         */
10115
10116                         n = fsig->param_count;
10117                         CHECK_STACK (n);
10118
10119                         /* 
10120                          * Generate smaller code for the common newobj <exception> instruction in
10121                          * argument checking code.
10122                          */
10123                         if (cfg->cbb->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
10124                                 is_exception_class (cmethod->klass) && n <= 2 &&
10125                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
10126                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
10127                                 MonoInst *iargs [3];
10128
10129                                 sp -= n;
10130
10131                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
10132                                 switch (n) {
10133                                 case 0:
10134                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
10135                                         break;
10136                                 case 1:
10137                                         iargs [1] = sp [0];
10138                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
10139                                         break;
10140                                 case 2:
10141                                         iargs [1] = sp [0];
10142                                         iargs [2] = sp [1];
10143                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
10144                                         break;
10145                                 default:
10146                                         g_assert_not_reached ();
10147                                 }
10148
10149                                 ip += 5;
10150                                 inline_costs += 5;
10151                                 break;
10152                         }
10153
10154                         /* move the args to allow room for 'this' in the first position */
10155                         while (n--) {
10156                                 --sp;
10157                                 sp [1] = sp [0];
10158                         }
10159
10160                         /* check_call_signature () requires sp[0] to be set */
10161                         this_ins.type = STACK_OBJ;
10162                         sp [0] = &this_ins;
10163                         if (check_call_signature (cfg, fsig, sp))
10164                                 UNVERIFIED;
10165
10166                         iargs [0] = NULL;
10167
10168                         if (mini_class_is_system_array (cmethod->klass)) {
10169                                 *sp = emit_get_rgctx_method (cfg, context_used,
10170                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
10171
10172                                 /* Avoid varargs in the common case */
10173                                 if (fsig->param_count == 1)
10174                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
10175                                 else if (fsig->param_count == 2)
10176                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
10177                                 else if (fsig->param_count == 3)
10178                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
10179                                 else if (fsig->param_count == 4)
10180                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
10181                                 else
10182                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
10183                         } else if (cmethod->string_ctor) {
10184                                 g_assert (!context_used);
10185                                 g_assert (!vtable_arg);
10186                                 /* we simply pass a null pointer */
10187                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
10188                                 /* now call the string ctor */
10189                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
10190                         } else {
10191                                 if (cmethod->klass->valuetype) {
10192                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
10193                                         emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
10194                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
10195
10196                                         alloc = NULL;
10197
10198                                         /* 
10199                                          * The code generated by mini_emit_virtual_call () expects
10200                                          * iargs [0] to be a boxed instance, but luckily the vcall
10201                                          * will be transformed into a normal call there.
10202                                          */
10203                                 } else if (context_used) {
10204                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
10205                                         *sp = alloc;
10206                                 } else {
10207                                         MonoVTable *vtable = NULL;
10208
10209                                         if (!cfg->compile_aot)
10210                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
10211                                         CHECK_TYPELOAD (cmethod->klass);
10212
10213                                         /*
10214                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
10215                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
10216                                          * As a workaround, we call class cctors before allocating objects.
10217                                          */
10218                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
10219                                                 emit_class_init (cfg, cmethod->klass);
10220                                                 if (cfg->verbose_level > 2)
10221                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
10222                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
10223                                         }
10224
10225                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
10226                                         *sp = alloc;
10227                                 }
10228                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
10229
10230                                 if (alloc)
10231                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
10232
10233                                 /* Now call the actual ctor */
10234                                 handle_ctor_call (cfg, cmethod, fsig, context_used, sp, ip, &inline_costs);
10235                                 CHECK_CFG_EXCEPTION;
10236                         }
10237
10238                         if (alloc == NULL) {
10239                                 /* Valuetype */
10240                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
10241                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
10242                                 *sp++= ins;
10243                         } else {
10244                                 *sp++ = alloc;
10245                         }
10246                         
10247                         ip += 5;
10248                         inline_costs += 5;
10249                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip - header->code)))
10250                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10251                         break;
10252                 }
10253                 case CEE_CASTCLASS:
10254                 case CEE_ISINST: {
10255                         CHECK_STACK (1);
10256                         --sp;
10257                         CHECK_OPSIZE (5);
10258                         token = read32 (ip + 1);
10259                         klass = mini_get_class (method, token, generic_context);
10260                         CHECK_TYPELOAD (klass);
10261                         if (sp [0]->type != STACK_OBJ)
10262                                 UNVERIFIED;
10263
10264                         MONO_INST_NEW (cfg, ins, *ip == CEE_ISINST ? OP_ISINST : OP_CASTCLASS);
10265                         ins->dreg = alloc_preg (cfg);
10266                         ins->sreg1 = (*sp)->dreg;
10267                         ins->klass = klass;
10268                         ins->type = STACK_OBJ;
10269                         MONO_ADD_INS (cfg->cbb, ins);
10270
10271                         CHECK_CFG_EXCEPTION;
10272                         *sp++ = ins;
10273                         ip += 5;
10274
10275                         cfg->flags |= MONO_CFG_HAS_TYPE_CHECK;
10276                         break;
10277                 }
10278                 case CEE_UNBOX_ANY: {
10279                         MonoInst *res, *addr;
10280
10281                         CHECK_STACK (1);
10282                         --sp;
10283                         CHECK_OPSIZE (5);
10284                         token = read32 (ip + 1);
10285                         klass = mini_get_class (method, token, generic_context);
10286                         CHECK_TYPELOAD (klass);
10287
10288                         mono_save_token_info (cfg, image, token, klass);
10289
10290                         context_used = mini_class_check_context_used (cfg, klass);
10291
10292                         if (mini_is_gsharedvt_klass (klass)) {
10293                                 res = handle_unbox_gsharedvt (cfg, klass, *sp);
10294                                 inline_costs += 2;
10295                         } else if (generic_class_is_reference_type (cfg, klass)) {
10296                                 if (MONO_INS_IS_PCONST_NULL (*sp)) {
10297                                         EMIT_NEW_PCONST (cfg, res, NULL);
10298                                         res->type = STACK_OBJ;
10299                                 } else {
10300                                         MONO_INST_NEW (cfg, res, OP_CASTCLASS);
10301                                         res->dreg = alloc_preg (cfg);
10302                                         res->sreg1 = (*sp)->dreg;
10303                                         res->klass = klass;
10304                                         res->type = STACK_OBJ;
10305                                         MONO_ADD_INS (cfg->cbb, res);
10306                                         cfg->flags |= MONO_CFG_HAS_TYPE_CHECK;
10307                                 }
10308                         } else if (mono_class_is_nullable (klass)) {
10309                                 res = handle_unbox_nullable (cfg, *sp, klass, context_used);
10310                         } else {
10311                                 addr = handle_unbox (cfg, klass, sp, context_used);
10312                                 /* LDOBJ */
10313                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
10314                                 res = ins;
10315                                 inline_costs += 2;
10316                         }
10317
10318                         *sp ++ = res;
10319                         ip += 5;
10320                         break;
10321                 }
10322                 case CEE_BOX: {
10323                         MonoInst *val;
10324                         MonoClass *enum_class;
10325                         MonoMethod *has_flag;
10326
10327                         CHECK_STACK (1);
10328                         --sp;
10329                         val = *sp;
10330                         CHECK_OPSIZE (5);
10331                         token = read32 (ip + 1);
10332                         klass = mini_get_class (method, token, generic_context);
10333                         CHECK_TYPELOAD (klass);
10334
10335                         mono_save_token_info (cfg, image, token, klass);
10336
10337                         context_used = mini_class_check_context_used (cfg, klass);
10338
10339                         if (generic_class_is_reference_type (cfg, klass)) {
10340                                 *sp++ = val;
10341                                 ip += 5;
10342                                 break;
10343                         }
10344
10345                         if (klass == mono_defaults.void_class)
10346                                 UNVERIFIED;
10347                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
10348                                 UNVERIFIED;
10349                         /* frequent check in generic code: box (struct), brtrue */
10350
10351                         /*
10352                          * Look for:
10353                          *
10354                          *   <push int/long ptr>
10355                          *   <push int/long>
10356                          *   box MyFlags
10357                          *   constrained. MyFlags
10358                          *   callvirt instace bool class [mscorlib] System.Enum::HasFlag (class [mscorlib] System.Enum)
10359                          *
10360                          * If we find this sequence and the operand types on box and constrained
10361                          * are equal, we can emit a specialized instruction sequence instead of
10362                          * the very slow HasFlag () call.
10363                          */
10364                         if ((cfg->opt & MONO_OPT_INTRINS) &&
10365                             /* Cheap checks first. */
10366                             ip + 5 + 6 + 5 < end &&
10367                             ip [5] == CEE_PREFIX1 &&
10368                             ip [6] == CEE_CONSTRAINED_ &&
10369                             ip [11] == CEE_CALLVIRT &&
10370                             ip_in_bb (cfg, cfg->cbb, ip + 5 + 6 + 5) &&
10371                             mono_class_is_enum (klass) &&
10372                             (enum_class = mini_get_class (method, read32 (ip + 7), generic_context)) &&
10373                             (has_flag = mini_get_method (cfg, method, read32 (ip + 12), NULL, generic_context)) &&
10374                             has_flag->klass == mono_defaults.enum_class &&
10375                             !strcmp (has_flag->name, "HasFlag") &&
10376                             has_flag->signature->hasthis &&
10377                             has_flag->signature->param_count == 1) {
10378                                 CHECK_TYPELOAD (enum_class);
10379
10380                                 if (enum_class == klass) {
10381                                         MonoInst *enum_this, *enum_flag;
10382
10383                                         ip += 5 + 6 + 5;
10384                                         --sp;
10385
10386                                         enum_this = sp [0];
10387                                         enum_flag = sp [1];
10388
10389                                         *sp++ = handle_enum_has_flag (cfg, klass, enum_this, enum_flag);
10390                                         break;
10391                                 }
10392                         }
10393
10394                         // FIXME: LLVM can't handle the inconsistent bb linking
10395                         if (!mono_class_is_nullable (klass) &&
10396                                 !mini_is_gsharedvt_klass (klass) &&
10397                                 ip + 5 < end && ip_in_bb (cfg, cfg->cbb, ip + 5) &&
10398                                 (ip [5] == CEE_BRTRUE || 
10399                                  ip [5] == CEE_BRTRUE_S ||
10400                                  ip [5] == CEE_BRFALSE ||
10401                                  ip [5] == CEE_BRFALSE_S)) {
10402                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
10403                                 int dreg;
10404                                 MonoBasicBlock *true_bb, *false_bb;
10405
10406                                 ip += 5;
10407
10408                                 if (cfg->verbose_level > 3) {
10409                                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
10410                                         printf ("<box+brtrue opt>\n");
10411                                 }
10412
10413                                 switch (*ip) {
10414                                 case CEE_BRTRUE_S:
10415                                 case CEE_BRFALSE_S:
10416                                         CHECK_OPSIZE (2);
10417                                         ip++;
10418                                         target = ip + 1 + (signed char)(*ip);
10419                                         ip++;
10420                                         break;
10421                                 case CEE_BRTRUE:
10422                                 case CEE_BRFALSE:
10423                                         CHECK_OPSIZE (5);
10424                                         ip++;
10425                                         target = ip + 4 + (gint)(read32 (ip));
10426                                         ip += 4;
10427                                         break;
10428                                 default:
10429                                         g_assert_not_reached ();
10430                                 }
10431
10432                                 /* 
10433                                  * We need to link both bblocks, since it is needed for handling stack
10434                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
10435                                  * Branching to only one of them would lead to inconsistencies, so
10436                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
10437                                  */
10438                                 GET_BBLOCK (cfg, true_bb, target);
10439                                 GET_BBLOCK (cfg, false_bb, ip);
10440
10441                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
10442                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
10443
10444                                 if (sp != stack_start) {
10445                                         handle_stack_args (cfg, stack_start, sp - stack_start);
10446                                         sp = stack_start;
10447                                         CHECK_UNVERIFIABLE (cfg);
10448                                 }
10449
10450                                 if (COMPILE_LLVM (cfg)) {
10451                                         dreg = alloc_ireg (cfg);
10452                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
10453                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
10454
10455                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
10456                                 } else {
10457                                         /* The JIT can't eliminate the iconst+compare */
10458                                         MONO_INST_NEW (cfg, ins, OP_BR);
10459                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
10460                                         MONO_ADD_INS (cfg->cbb, ins);
10461                                 }
10462
10463                                 start_new_bblock = 1;
10464                                 break;
10465                         }
10466
10467                         *sp++ = handle_box (cfg, val, klass, context_used);
10468
10469                         CHECK_CFG_EXCEPTION;
10470                         ip += 5;
10471                         inline_costs += 1;
10472                         break;
10473                 }
10474                 case CEE_UNBOX: {
10475                         CHECK_STACK (1);
10476                         --sp;
10477                         CHECK_OPSIZE (5);
10478                         token = read32 (ip + 1);
10479                         klass = mini_get_class (method, token, generic_context);
10480                         CHECK_TYPELOAD (klass);
10481
10482                         mono_save_token_info (cfg, image, token, klass);
10483
10484                         context_used = mini_class_check_context_used (cfg, klass);
10485
10486                         if (mono_class_is_nullable (klass)) {
10487                                 MonoInst *val;
10488
10489                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
10490                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
10491
10492                                 *sp++= ins;
10493                         } else {
10494                                 ins = handle_unbox (cfg, klass, sp, context_used);
10495                                 *sp++ = ins;
10496                         }
10497                         ip += 5;
10498                         inline_costs += 2;
10499                         break;
10500                 }
10501                 case CEE_LDFLD:
10502                 case CEE_LDFLDA:
10503                 case CEE_STFLD:
10504                 case CEE_LDSFLD:
10505                 case CEE_LDSFLDA:
10506                 case CEE_STSFLD: {
10507                         MonoClassField *field;
10508 #ifndef DISABLE_REMOTING
10509                         int costs;
10510 #endif
10511                         guint foffset;
10512                         gboolean is_instance;
10513                         int op;
10514                         gpointer addr = NULL;
10515                         gboolean is_special_static;
10516                         MonoType *ftype;
10517                         MonoInst *store_val = NULL;
10518                         MonoInst *thread_ins;
10519
10520                         op = *ip;
10521                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
10522                         if (is_instance) {
10523                                 if (op == CEE_STFLD) {
10524                                         CHECK_STACK (2);
10525                                         sp -= 2;
10526                                         store_val = sp [1];
10527                                 } else {
10528                                         CHECK_STACK (1);
10529                                         --sp;
10530                                 }
10531                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
10532                                         UNVERIFIED;
10533                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
10534                                         UNVERIFIED;
10535                         } else {
10536                                 if (op == CEE_STSFLD) {
10537                                         CHECK_STACK (1);
10538                                         sp--;
10539                                         store_val = sp [0];
10540                                 }
10541                         }
10542
10543                         CHECK_OPSIZE (5);
10544                         token = read32 (ip + 1);
10545                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
10546                                 field = (MonoClassField *)mono_method_get_wrapper_data (method, token);
10547                                 klass = field->parent;
10548                         }
10549                         else {
10550                                 field = mono_field_from_token_checked (image, token, &klass, generic_context, &cfg->error);
10551                                 CHECK_CFG_ERROR;
10552                         }
10553                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
10554                                 FIELD_ACCESS_FAILURE (method, field);
10555                         mono_class_init (klass);
10556
10557                         /* if the class is Critical then transparent code cannot access it's fields */
10558                         if (!is_instance && mono_security_core_clr_enabled ())
10559                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
10560
10561                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
10562                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
10563                         if (mono_security_core_clr_enabled ())
10564                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
10565                         */
10566
10567                         ftype = mono_field_get_type (field);
10568
10569                         /*
10570                          * LDFLD etc. is usable on static fields as well, so convert those cases to
10571                          * the static case.
10572                          */
10573                         if (is_instance && ftype->attrs & FIELD_ATTRIBUTE_STATIC) {
10574                                 switch (op) {
10575                                 case CEE_LDFLD:
10576                                         op = CEE_LDSFLD;
10577                                         break;
10578                                 case CEE_STFLD:
10579                                         op = CEE_STSFLD;
10580                                         break;
10581                                 case CEE_LDFLDA:
10582                                         op = CEE_LDSFLDA;
10583                                         break;
10584                                 default:
10585                                         g_assert_not_reached ();
10586                                 }
10587                                 is_instance = FALSE;
10588                         }
10589
10590                         context_used = mini_class_check_context_used (cfg, klass);
10591
10592                         /* INSTANCE CASE */
10593
10594                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
10595                         if (op == CEE_STFLD) {
10596                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
10597                                         UNVERIFIED;
10598 #ifndef DISABLE_REMOTING
10599                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
10600                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
10601                                         MonoInst *iargs [5];
10602
10603                                         GSHAREDVT_FAILURE (op);
10604
10605                                         iargs [0] = sp [0];
10606                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10607                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
10608                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
10609                                                     field->offset);
10610                                         iargs [4] = sp [1];
10611
10612                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
10613                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
10614                                                                                            iargs, ip, cfg->real_offset, TRUE);
10615                                                 CHECK_CFG_EXCEPTION;
10616                                                 g_assert (costs > 0);
10617                                                       
10618                                                 cfg->real_offset += 5;
10619
10620                                                 inline_costs += costs;
10621                                         } else {
10622                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
10623                                         }
10624                                 } else
10625 #endif
10626                                 {
10627                                         MonoInst *store, *wbarrier_ptr_ins = NULL;
10628
10629                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
10630
10631                                         if (ins_flag & MONO_INST_VOLATILE) {
10632                                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
10633                                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
10634                                         }
10635
10636                                         if (mini_is_gsharedvt_klass (klass)) {
10637                                                 MonoInst *offset_ins;
10638
10639                                                 context_used = mini_class_check_context_used (cfg, klass);
10640
10641                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10642                                                 /* The value is offset by 1 */
10643                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
10644                                                 dreg = alloc_ireg_mp (cfg);
10645                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10646                                                 wbarrier_ptr_ins = ins;
10647                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
10648                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
10649                                         } else {
10650                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
10651                                         }
10652                                         if (sp [0]->opcode != OP_LDADDR)
10653                                                 store->flags |= MONO_INST_FAULT;
10654
10655                                         if (cfg->gen_write_barriers && mini_type_to_stind (cfg, field->type) == CEE_STIND_REF && !MONO_INS_IS_PCONST_NULL (sp [1])) {
10656                                                 if (mini_is_gsharedvt_klass (klass)) {
10657                                                         g_assert (wbarrier_ptr_ins);
10658                                                         emit_write_barrier (cfg, wbarrier_ptr_ins, sp [1]);
10659                                                 } else {
10660                                                         /* insert call to write barrier */
10661                                                         MonoInst *ptr;
10662                                                         int dreg;
10663
10664                                                         dreg = alloc_ireg_mp (cfg);
10665                                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10666                                                         emit_write_barrier (cfg, ptr, sp [1]);
10667                                                 }
10668                                         }
10669
10670                                         store->flags |= ins_flag;
10671                                 }
10672                                 ins_flag = 0;
10673                                 ip += 5;
10674                                 break;
10675                         }
10676
10677 #ifndef DISABLE_REMOTING
10678                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
10679                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
10680                                 MonoInst *iargs [4];
10681
10682                                 GSHAREDVT_FAILURE (op);
10683
10684                                 iargs [0] = sp [0];
10685                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10686                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
10687                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
10688                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
10689                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
10690                                                                                    iargs, ip, cfg->real_offset, TRUE);
10691                                         CHECK_CFG_EXCEPTION;
10692                                         g_assert (costs > 0);
10693                                                       
10694                                         cfg->real_offset += 5;
10695
10696                                         *sp++ = iargs [0];
10697
10698                                         inline_costs += costs;
10699                                 } else {
10700                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
10701                                         *sp++ = ins;
10702                                 }
10703                         } else 
10704 #endif
10705                         if (is_instance) {
10706                                 if (sp [0]->type == STACK_VTYPE) {
10707                                         MonoInst *var;
10708
10709                                         /* Have to compute the address of the variable */
10710
10711                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
10712                                         if (!var)
10713                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
10714                                         else
10715                                                 g_assert (var->klass == klass);
10716                                         
10717                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
10718                                         sp [0] = ins;
10719                                 }
10720
10721                                 if (op == CEE_LDFLDA) {
10722                                         if (sp [0]->type == STACK_OBJ) {
10723                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
10724                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
10725                                         }
10726
10727                                         dreg = alloc_ireg_mp (cfg);
10728
10729                                         if (mini_is_gsharedvt_klass (klass)) {
10730                                                 MonoInst *offset_ins;
10731
10732                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10733                                                 /* The value is offset by 1 */
10734                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
10735                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10736                                         } else {
10737                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10738                                         }
10739                                         ins->klass = mono_class_from_mono_type (field->type);
10740                                         ins->type = STACK_MP;
10741                                         *sp++ = ins;
10742                                 } else {
10743                                         MonoInst *load;
10744
10745                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
10746
10747                                         if (sp [0]->opcode == OP_LDADDR && klass->simd_type && cfg->opt & MONO_OPT_SIMD) {
10748                                                 ins = mono_emit_simd_field_load (cfg, field, sp [0]);
10749                                                 if (ins) {
10750                                                         *sp++ = ins;
10751                                                         ins_flag = 0;
10752                                                         ip += 5;
10753                                                         break;
10754                                                 }
10755                                         }
10756
10757                                         if (mini_is_gsharedvt_klass (klass)) {
10758                                                 MonoInst *offset_ins;
10759
10760                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10761                                                 /* The value is offset by 1 */
10762                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
10763                                                 dreg = alloc_ireg_mp (cfg);
10764                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10765                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
10766                                         } else {
10767                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
10768                                         }
10769                                         load->flags |= ins_flag;
10770                                         if (sp [0]->opcode != OP_LDADDR)
10771                                                 load->flags |= MONO_INST_FAULT;
10772                                         *sp++ = load;
10773                                 }
10774                         }
10775
10776                         if (is_instance) {
10777                                 ins_flag = 0;
10778                                 ip += 5;
10779                                 break;
10780                         }
10781
10782                         /* STATIC CASE */
10783                         context_used = mini_class_check_context_used (cfg, klass);
10784
10785                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL) {
10786                                 mono_error_set_field_load (&cfg->error, field->parent, field->name, "Using static instructions with literal field");
10787                                 CHECK_CFG_ERROR;
10788                         }
10789
10790                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
10791                          * to be called here.
10792                          */
10793                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
10794                                 mono_class_vtable (cfg->domain, klass);
10795                                 CHECK_TYPELOAD (klass);
10796                         }
10797                         mono_domain_lock (cfg->domain);
10798                         if (cfg->domain->special_static_fields)
10799                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
10800                         mono_domain_unlock (cfg->domain);
10801
10802                         is_special_static = mono_class_field_is_special_static (field);
10803
10804                         if (is_special_static && ((gsize)addr & 0x80000000) == 0)
10805                                 thread_ins = mono_get_thread_intrinsic (cfg);
10806                         else
10807                                 thread_ins = NULL;
10808
10809                         /* Generate IR to compute the field address */
10810                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
10811                                 /*
10812                                  * Fast access to TLS data
10813                                  * Inline version of get_thread_static_data () in
10814                                  * threads.c.
10815                                  */
10816                                 guint32 offset;
10817                                 int idx, static_data_reg, array_reg, dreg;
10818
10819                                 GSHAREDVT_FAILURE (op);
10820
10821                                 MONO_ADD_INS (cfg->cbb, thread_ins);
10822                                 static_data_reg = alloc_ireg (cfg);
10823                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
10824
10825                                 if (cfg->compile_aot) {
10826                                         int offset_reg, offset2_reg, idx_reg;
10827
10828                                         /* For TLS variables, this will return the TLS offset */
10829                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
10830                                         offset_reg = ins->dreg;
10831                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
10832                                         idx_reg = alloc_ireg (cfg);
10833                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, idx_reg, offset_reg, 0x3f);
10834                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
10835                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
10836                                         array_reg = alloc_ireg (cfg);
10837                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
10838                                         offset2_reg = alloc_ireg (cfg);
10839                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, offset2_reg, offset_reg, 6);
10840                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset2_reg, 0x1ffffff);
10841                                         dreg = alloc_ireg (cfg);
10842                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
10843                                 } else {
10844                                         offset = (gsize)addr & 0x7fffffff;
10845                                         idx = offset & 0x3f;
10846
10847                                         array_reg = alloc_ireg (cfg);
10848                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
10849                                         dreg = alloc_ireg (cfg);
10850                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, ((offset >> 6) & 0x1ffffff));
10851                                 }
10852                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
10853                                         (cfg->compile_aot && is_special_static) ||
10854                                         (context_used && is_special_static)) {
10855                                 MonoInst *iargs [2];
10856
10857                                 g_assert (field->parent);
10858                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10859                                 if (context_used) {
10860                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
10861                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
10862                                 } else {
10863                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
10864                                 }
10865                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
10866                         } else if (context_used) {
10867                                 MonoInst *static_data;
10868
10869                                 /*
10870                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
10871                                         method->klass->name_space, method->klass->name, method->name,
10872                                         depth, field->offset);
10873                                 */
10874
10875                                 if (mono_class_needs_cctor_run (klass, method))
10876                                         emit_class_init (cfg, klass);
10877
10878                                 /*
10879                                  * The pointer we're computing here is
10880                                  *
10881                                  *   super_info.static_data + field->offset
10882                                  */
10883                                 static_data = mini_emit_get_rgctx_klass (cfg, context_used,
10884                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
10885
10886                                 if (mini_is_gsharedvt_klass (klass)) {
10887                                         MonoInst *offset_ins;
10888
10889                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10890                                         /* The value is offset by 1 */
10891                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
10892                                         dreg = alloc_ireg_mp (cfg);
10893                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
10894                                 } else if (field->offset == 0) {
10895                                         ins = static_data;
10896                                 } else {
10897                                         int addr_reg = mono_alloc_preg (cfg);
10898                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
10899                                 }
10900                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
10901                                 MonoInst *iargs [2];
10902
10903                                 g_assert (field->parent);
10904                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10905                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
10906                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
10907                         } else {
10908                                 MonoVTable *vtable = NULL;
10909
10910                                 if (!cfg->compile_aot)
10911                                         vtable = mono_class_vtable (cfg->domain, klass);
10912                                 CHECK_TYPELOAD (klass);
10913
10914                                 if (!addr) {
10915                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
10916                                                 if (!(g_slist_find (class_inits, klass))) {
10917                                                         emit_class_init (cfg, klass);
10918                                                         if (cfg->verbose_level > 2)
10919                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
10920                                                         class_inits = g_slist_prepend (class_inits, klass);
10921                                                 }
10922                                         } else {
10923                                                 if (cfg->run_cctors) {
10924                                                         /* This makes so that inline cannot trigger */
10925                                                         /* .cctors: too many apps depend on them */
10926                                                         /* running with a specific order... */
10927                                                         g_assert (vtable);
10928                                                         if (! vtable->initialized)
10929                                                                 INLINE_FAILURE ("class init");
10930                                                         if (!mono_runtime_class_init_full (vtable, &cfg->error)) {
10931                                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
10932                                                                 goto exception_exit;
10933                                                         }
10934                                                 }
10935                                         }
10936                                         if (cfg->compile_aot)
10937                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
10938                                         else {
10939                                                 g_assert (vtable);
10940                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
10941                                                 g_assert (addr);
10942                                                 EMIT_NEW_PCONST (cfg, ins, addr);
10943                                         }
10944                                 } else {
10945                                         MonoInst *iargs [1];
10946                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
10947                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
10948                                 }
10949                         }
10950
10951                         /* Generate IR to do the actual load/store operation */
10952
10953                         if ((op == CEE_STFLD || op == CEE_STSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
10954                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
10955                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
10956                         }
10957
10958                         if (op == CEE_LDSFLDA) {
10959                                 ins->klass = mono_class_from_mono_type (ftype);
10960                                 ins->type = STACK_PTR;
10961                                 *sp++ = ins;
10962                         } else if (op == CEE_STSFLD) {
10963                                 MonoInst *store;
10964
10965                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
10966                                 store->flags |= ins_flag;
10967                         } else {
10968                                 gboolean is_const = FALSE;
10969                                 MonoVTable *vtable = NULL;
10970                                 gpointer addr = NULL;
10971
10972                                 if (!context_used) {
10973                                         vtable = mono_class_vtable (cfg->domain, klass);
10974                                         CHECK_TYPELOAD (klass);
10975                                 }
10976                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
10977                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
10978                                         int ro_type = ftype->type;
10979                                         if (!addr)
10980                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
10981                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
10982                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
10983                                         }
10984
10985                                         GSHAREDVT_FAILURE (op);
10986
10987                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
10988                                         is_const = TRUE;
10989                                         switch (ro_type) {
10990                                         case MONO_TYPE_BOOLEAN:
10991                                         case MONO_TYPE_U1:
10992                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
10993                                                 sp++;
10994                                                 break;
10995                                         case MONO_TYPE_I1:
10996                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
10997                                                 sp++;
10998                                                 break;                                          
10999                                         case MONO_TYPE_CHAR:
11000                                         case MONO_TYPE_U2:
11001                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
11002                                                 sp++;
11003                                                 break;
11004                                         case MONO_TYPE_I2:
11005                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
11006                                                 sp++;
11007                                                 break;
11008                                                 break;
11009                                         case MONO_TYPE_I4:
11010                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
11011                                                 sp++;
11012                                                 break;                                          
11013                                         case MONO_TYPE_U4:
11014                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
11015                                                 sp++;
11016                                                 break;
11017                                         case MONO_TYPE_I:
11018                                         case MONO_TYPE_U:
11019                                         case MONO_TYPE_PTR:
11020                                         case MONO_TYPE_FNPTR:
11021                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11022                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
11023                                                 sp++;
11024                                                 break;
11025                                         case MONO_TYPE_STRING:
11026                                         case MONO_TYPE_OBJECT:
11027                                         case MONO_TYPE_CLASS:
11028                                         case MONO_TYPE_SZARRAY:
11029                                         case MONO_TYPE_ARRAY:
11030                                                 if (!mono_gc_is_moving ()) {
11031                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11032                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
11033                                                         sp++;
11034                                                 } else {
11035                                                         is_const = FALSE;
11036                                                 }
11037                                                 break;
11038                                         case MONO_TYPE_I8:
11039                                         case MONO_TYPE_U8:
11040                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
11041                                                 sp++;
11042                                                 break;
11043                                         case MONO_TYPE_R4:
11044                                         case MONO_TYPE_R8:
11045                                         case MONO_TYPE_VALUETYPE:
11046                                         default:
11047                                                 is_const = FALSE;
11048                                                 break;
11049                                         }
11050                                 }
11051
11052                                 if (!is_const) {
11053                                         MonoInst *load;
11054
11055                                         CHECK_STACK_OVF (1);
11056
11057                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
11058                                         load->flags |= ins_flag;
11059                                         ins_flag = 0;
11060                                         *sp++ = load;
11061                                 }
11062                         }
11063
11064                         if ((op == CEE_LDFLD || op == CEE_LDSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11065                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
11066                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
11067                         }
11068
11069                         ins_flag = 0;
11070                         ip += 5;
11071                         break;
11072                 }
11073                 case CEE_STOBJ:
11074                         CHECK_STACK (2);
11075                         sp -= 2;
11076                         CHECK_OPSIZE (5);
11077                         token = read32 (ip + 1);
11078                         klass = mini_get_class (method, token, generic_context);
11079                         CHECK_TYPELOAD (klass);
11080                         if (ins_flag & MONO_INST_VOLATILE) {
11081                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11082                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11083                         }
11084                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
11085                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
11086                         ins->flags |= ins_flag;
11087                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
11088                                 generic_class_is_reference_type (cfg, klass) && !MONO_INS_IS_PCONST_NULL (sp [1])) {
11089                                 /* insert call to write barrier */
11090                                 emit_write_barrier (cfg, sp [0], sp [1]);
11091                         }
11092                         ins_flag = 0;
11093                         ip += 5;
11094                         inline_costs += 1;
11095                         break;
11096
11097                         /*
11098                          * Array opcodes
11099                          */
11100                 case CEE_NEWARR: {
11101                         MonoInst *len_ins;
11102                         const char *data_ptr;
11103                         int data_size = 0;
11104                         guint32 field_token;
11105
11106                         CHECK_STACK (1);
11107                         --sp;
11108
11109                         CHECK_OPSIZE (5);
11110                         token = read32 (ip + 1);
11111
11112                         klass = mini_get_class (method, token, generic_context);
11113                         CHECK_TYPELOAD (klass);
11114
11115                         context_used = mini_class_check_context_used (cfg, klass);
11116
11117                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
11118                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
11119                                 ins->sreg1 = sp [0]->dreg;
11120                                 ins->type = STACK_I4;
11121                                 ins->dreg = alloc_ireg (cfg);
11122                                 MONO_ADD_INS (cfg->cbb, ins);
11123                                 *sp = mono_decompose_opcode (cfg, ins);
11124                         }
11125
11126                         if (context_used) {
11127                                 MonoInst *args [3];
11128                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11129                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
11130
11131                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
11132
11133                                 /* vtable */
11134                                 args [0] = mini_emit_get_rgctx_klass (cfg, context_used,
11135                                         array_class, MONO_RGCTX_INFO_VTABLE);
11136                                 /* array len */
11137                                 args [1] = sp [0];
11138
11139                                 if (managed_alloc)
11140                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
11141                                 else
11142                                         ins = mono_emit_jit_icall (cfg, ves_icall_array_new_specific, args);
11143                         } else {
11144                                 if (cfg->opt & MONO_OPT_SHARED) {
11145                                         /* Decompose now to avoid problems with references to the domainvar */
11146                                         MonoInst *iargs [3];
11147
11148                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11149                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11150                                         iargs [2] = sp [0];
11151
11152                                         ins = mono_emit_jit_icall (cfg, ves_icall_array_new, iargs);
11153                                 } else {
11154                                         /* Decompose later since it is needed by abcrem */
11155                                         MonoClass *array_type = mono_array_class_get (klass, 1);
11156                                         mono_class_vtable (cfg->domain, array_type);
11157                                         CHECK_TYPELOAD (array_type);
11158
11159                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
11160                                         ins->dreg = alloc_ireg_ref (cfg);
11161                                         ins->sreg1 = sp [0]->dreg;
11162                                         ins->inst_newa_class = klass;
11163                                         ins->type = STACK_OBJ;
11164                                         ins->klass = array_type;
11165                                         MONO_ADD_INS (cfg->cbb, ins);
11166                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11167                                         cfg->cbb->has_array_access = TRUE;
11168
11169                                         /* Needed so mono_emit_load_get_addr () gets called */
11170                                         mono_get_got_var (cfg);
11171                                 }
11172                         }
11173
11174                         len_ins = sp [0];
11175                         ip += 5;
11176                         *sp++ = ins;
11177                         inline_costs += 1;
11178
11179                         /* 
11180                          * we inline/optimize the initialization sequence if possible.
11181                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
11182                          * for small sizes open code the memcpy
11183                          * ensure the rva field is big enough
11184                          */
11185                         if ((cfg->opt & MONO_OPT_INTRINS) && ip + 6 < end && ip_in_bb (cfg, cfg->cbb, ip + 6) && (len_ins->opcode == OP_ICONST) && (data_ptr = initialize_array_data (method, cfg->compile_aot, ip, klass, len_ins->inst_c0, &data_size, &field_token))) {
11186                                 MonoMethod *memcpy_method = get_memcpy_method ();
11187                                 MonoInst *iargs [3];
11188                                 int add_reg = alloc_ireg_mp (cfg);
11189
11190                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, MONO_STRUCT_OFFSET (MonoArray, vector));
11191                                 if (cfg->compile_aot) {
11192                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
11193                                 } else {
11194                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
11195                                 }
11196                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
11197                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
11198                                 ip += 11;
11199                         }
11200
11201                         break;
11202                 }
11203                 case CEE_LDLEN:
11204                         CHECK_STACK (1);
11205                         --sp;
11206                         if (sp [0]->type != STACK_OBJ)
11207                                 UNVERIFIED;
11208
11209                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
11210                         ins->dreg = alloc_preg (cfg);
11211                         ins->sreg1 = sp [0]->dreg;
11212                         ins->type = STACK_I4;
11213                         /* This flag will be inherited by the decomposition */
11214                         ins->flags |= MONO_INST_FAULT;
11215                         MONO_ADD_INS (cfg->cbb, ins);
11216                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11217                         cfg->cbb->has_array_access = TRUE;
11218                         ip ++;
11219                         *sp++ = ins;
11220                         break;
11221                 case CEE_LDELEMA:
11222                         CHECK_STACK (2);
11223                         sp -= 2;
11224                         CHECK_OPSIZE (5);
11225                         if (sp [0]->type != STACK_OBJ)
11226                                 UNVERIFIED;
11227
11228                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11229
11230                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11231                         CHECK_TYPELOAD (klass);
11232                         /* we need to make sure that this array is exactly the type it needs
11233                          * to be for correctness. the wrappers are lax with their usage
11234                          * so we need to ignore them here
11235                          */
11236                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
11237                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11238                                 mini_emit_check_array_type (cfg, sp [0], array_class);
11239                                 CHECK_TYPELOAD (array_class);
11240                         }
11241
11242                         readonly = FALSE;
11243                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11244                         *sp++ = ins;
11245                         ip += 5;
11246                         break;
11247                 case CEE_LDELEM:
11248                 case CEE_LDELEM_I1:
11249                 case CEE_LDELEM_U1:
11250                 case CEE_LDELEM_I2:
11251                 case CEE_LDELEM_U2:
11252                 case CEE_LDELEM_I4:
11253                 case CEE_LDELEM_U4:
11254                 case CEE_LDELEM_I8:
11255                 case CEE_LDELEM_I:
11256                 case CEE_LDELEM_R4:
11257                 case CEE_LDELEM_R8:
11258                 case CEE_LDELEM_REF: {
11259                         MonoInst *addr;
11260
11261                         CHECK_STACK (2);
11262                         sp -= 2;
11263
11264                         if (*ip == CEE_LDELEM) {
11265                                 CHECK_OPSIZE (5);
11266                                 token = read32 (ip + 1);
11267                                 klass = mini_get_class (method, token, generic_context);
11268                                 CHECK_TYPELOAD (klass);
11269                                 mono_class_init (klass);
11270                         }
11271                         else
11272                                 klass = array_access_to_klass (*ip);
11273
11274                         if (sp [0]->type != STACK_OBJ)
11275                                 UNVERIFIED;
11276
11277                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11278
11279                         if (mini_is_gsharedvt_variable_klass (klass)) {
11280                                 // FIXME-VT: OP_ICONST optimization
11281                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11282                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11283                                 ins->opcode = OP_LOADV_MEMBASE;
11284                         } else if (sp [1]->opcode == OP_ICONST) {
11285                                 int array_reg = sp [0]->dreg;
11286                                 int index_reg = sp [1]->dreg;
11287                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
11288
11289                                 if (SIZEOF_REGISTER == 8 && COMPILE_LLVM (cfg))
11290                                         MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, index_reg);
11291
11292                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
11293                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
11294                         } else {
11295                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11296                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11297                         }
11298                         *sp++ = ins;
11299                         if (*ip == CEE_LDELEM)
11300                                 ip += 5;
11301                         else
11302                                 ++ip;
11303                         break;
11304                 }
11305                 case CEE_STELEM_I:
11306                 case CEE_STELEM_I1:
11307                 case CEE_STELEM_I2:
11308                 case CEE_STELEM_I4:
11309                 case CEE_STELEM_I8:
11310                 case CEE_STELEM_R4:
11311                 case CEE_STELEM_R8:
11312                 case CEE_STELEM_REF:
11313                 case CEE_STELEM: {
11314                         CHECK_STACK (3);
11315                         sp -= 3;
11316
11317                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11318
11319                         if (*ip == CEE_STELEM) {
11320                                 CHECK_OPSIZE (5);
11321                                 token = read32 (ip + 1);
11322                                 klass = mini_get_class (method, token, generic_context);
11323                                 CHECK_TYPELOAD (klass);
11324                                 mono_class_init (klass);
11325                         }
11326                         else
11327                                 klass = array_access_to_klass (*ip);
11328
11329                         if (sp [0]->type != STACK_OBJ)
11330                                 UNVERIFIED;
11331
11332                         emit_array_store (cfg, klass, sp, TRUE);
11333
11334                         if (*ip == CEE_STELEM)
11335                                 ip += 5;
11336                         else
11337                                 ++ip;
11338                         inline_costs += 1;
11339                         break;
11340                 }
11341                 case CEE_CKFINITE: {
11342                         CHECK_STACK (1);
11343                         --sp;
11344
11345                         if (cfg->llvm_only) {
11346                                 MonoInst *iargs [1];
11347
11348                                 iargs [0] = sp [0];
11349                                 *sp++ = mono_emit_jit_icall (cfg, mono_ckfinite, iargs);
11350                         } else  {
11351                                 MONO_INST_NEW (cfg, ins, OP_CKFINITE);
11352                                 ins->sreg1 = sp [0]->dreg;
11353                                 ins->dreg = alloc_freg (cfg);
11354                                 ins->type = STACK_R8;
11355                                 MONO_ADD_INS (cfg->cbb, ins);
11356
11357                                 *sp++ = mono_decompose_opcode (cfg, ins);
11358                         }
11359
11360                         ++ip;
11361                         break;
11362                 }
11363                 case CEE_REFANYVAL: {
11364                         MonoInst *src_var, *src;
11365
11366                         int klass_reg = alloc_preg (cfg);
11367                         int dreg = alloc_preg (cfg);
11368
11369                         GSHAREDVT_FAILURE (*ip);
11370
11371                         CHECK_STACK (1);
11372                         MONO_INST_NEW (cfg, ins, *ip);
11373                         --sp;
11374                         CHECK_OPSIZE (5);
11375                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11376                         CHECK_TYPELOAD (klass);
11377
11378                         context_used = mini_class_check_context_used (cfg, klass);
11379
11380                         // FIXME:
11381                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11382                         if (!src_var)
11383                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
11384                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
11385                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass));
11386
11387                         if (context_used) {
11388                                 MonoInst *klass_ins;
11389
11390                                 klass_ins = mini_emit_get_rgctx_klass (cfg, context_used,
11391                                                 klass, MONO_RGCTX_INFO_KLASS);
11392
11393                                 // FIXME:
11394                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
11395                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
11396                         } else {
11397                                 mini_emit_class_check (cfg, klass_reg, klass);
11398                         }
11399                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value));
11400                         ins->type = STACK_MP;
11401                         ins->klass = klass;
11402                         *sp++ = ins;
11403                         ip += 5;
11404                         break;
11405                 }
11406                 case CEE_MKREFANY: {
11407                         MonoInst *loc, *addr;
11408
11409                         GSHAREDVT_FAILURE (*ip);
11410
11411                         CHECK_STACK (1);
11412                         MONO_INST_NEW (cfg, ins, *ip);
11413                         --sp;
11414                         CHECK_OPSIZE (5);
11415                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11416                         CHECK_TYPELOAD (klass);
11417
11418                         context_used = mini_class_check_context_used (cfg, klass);
11419
11420                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
11421                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
11422
11423                         if (context_used) {
11424                                 MonoInst *const_ins;
11425                                 int type_reg = alloc_preg (cfg);
11426
11427                                 const_ins = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
11428                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
11429                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11430                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11431                         } else {
11432                                 int const_reg = alloc_preg (cfg);
11433                                 int type_reg = alloc_preg (cfg);
11434
11435                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
11436                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
11437                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11438                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11439                         }
11440                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
11441
11442                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
11443                         ins->type = STACK_VTYPE;
11444                         ins->klass = mono_defaults.typed_reference_class;
11445                         *sp++ = ins;
11446                         ip += 5;
11447                         break;
11448                 }
11449                 case CEE_LDTOKEN: {
11450                         gpointer handle;
11451                         MonoClass *handle_class;
11452
11453                         CHECK_STACK_OVF (1);
11454
11455                         CHECK_OPSIZE (5);
11456                         n = read32 (ip + 1);
11457
11458                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
11459                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
11460                                 handle = mono_method_get_wrapper_data (method, n);
11461                                 handle_class = (MonoClass *)mono_method_get_wrapper_data (method, n + 1);
11462                                 if (handle_class == mono_defaults.typehandle_class)
11463                                         handle = &((MonoClass*)handle)->byval_arg;
11464                         }
11465                         else {
11466                                 handle = mono_ldtoken_checked (image, n, &handle_class, generic_context, &cfg->error);
11467                                 CHECK_CFG_ERROR;
11468                         }
11469                         if (!handle)
11470                                 LOAD_ERROR;
11471                         mono_class_init (handle_class);
11472                         if (cfg->gshared) {
11473                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
11474                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
11475                                         /* This case handles ldtoken
11476                                            of an open type, like for
11477                                            typeof(Gen<>). */
11478                                         context_used = 0;
11479                                 } else if (handle_class == mono_defaults.typehandle_class) {
11480                                         context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type ((MonoType *)handle));
11481                                 } else if (handle_class == mono_defaults.fieldhandle_class)
11482                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
11483                                 else if (handle_class == mono_defaults.methodhandle_class)
11484                                         context_used = mini_method_check_context_used (cfg, (MonoMethod *)handle);
11485                                 else
11486                                         g_assert_not_reached ();
11487                         }
11488
11489                         if ((cfg->opt & MONO_OPT_SHARED) &&
11490                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
11491                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
11492                                 MonoInst *addr, *vtvar, *iargs [3];
11493                                 int method_context_used;
11494
11495                                 method_context_used = mini_method_check_context_used (cfg, method);
11496
11497                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
11498
11499                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
11500                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
11501                                 if (method_context_used) {
11502                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
11503                                                 method, MONO_RGCTX_INFO_METHOD);
11504                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
11505                                 } else {
11506                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
11507                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
11508                                 }
11509                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11510
11511                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11512
11513                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11514                         } else {
11515                                 if ((ip + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 5) && 
11516                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
11517                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
11518                                         (cmethod->klass == mono_defaults.systemtype_class) &&
11519                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
11520                                         MonoClass *tclass = mono_class_from_mono_type ((MonoType *)handle);
11521
11522                                         mono_class_init (tclass);
11523                                         if (context_used) {
11524                                                 ins = mini_emit_get_rgctx_klass (cfg, context_used,
11525                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
11526                                         } else if (cfg->compile_aot) {
11527                                                 if (method->wrapper_type) {
11528                                                         mono_error_init (&error); //got to do it since there are multiple conditionals below
11529                                                         if (mono_class_get_checked (tclass->image, tclass->type_token, &error) == tclass && !generic_context) {
11530                                                                 /* Special case for static synchronized wrappers */
11531                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
11532                                                         } else {
11533                                                                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
11534                                                                 /* FIXME: n is not a normal token */
11535                                                                 DISABLE_AOT (cfg);
11536                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11537                                                         }
11538                                                 } else {
11539                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
11540                                                 }
11541                                         } else {
11542                                                 MonoReflectionType *rt = mono_type_get_object_checked (cfg->domain, (MonoType *)handle, &cfg->error);
11543                                                 CHECK_CFG_ERROR;
11544                                                 EMIT_NEW_PCONST (cfg, ins, rt);
11545                                         }
11546                                         ins->type = STACK_OBJ;
11547                                         ins->klass = cmethod->klass;
11548                                         ip += 5;
11549                                 } else {
11550                                         MonoInst *addr, *vtvar;
11551
11552                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
11553
11554                                         if (context_used) {
11555                                                 if (handle_class == mono_defaults.typehandle_class) {
11556                                                         ins = mini_emit_get_rgctx_klass (cfg, context_used,
11557                                                                         mono_class_from_mono_type ((MonoType *)handle),
11558                                                                         MONO_RGCTX_INFO_TYPE);
11559                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
11560                                                         ins = emit_get_rgctx_method (cfg, context_used,
11561                                                                         (MonoMethod *)handle, MONO_RGCTX_INFO_METHOD);
11562                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
11563                                                         ins = emit_get_rgctx_field (cfg, context_used,
11564                                                                         (MonoClassField *)handle, MONO_RGCTX_INFO_CLASS_FIELD);
11565                                                 } else {
11566                                                         g_assert_not_reached ();
11567                                                 }
11568                                         } else if (cfg->compile_aot) {
11569                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
11570                                         } else {
11571                                                 EMIT_NEW_PCONST (cfg, ins, handle);
11572                                         }
11573                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11574                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11575                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11576                                 }
11577                         }
11578
11579                         *sp++ = ins;
11580                         ip += 5;
11581                         break;
11582                 }
11583                 case CEE_THROW:
11584                         CHECK_STACK (1);
11585                         if (sp [-1]->type != STACK_OBJ)
11586                                 UNVERIFIED;
11587
11588                         MONO_INST_NEW (cfg, ins, OP_THROW);
11589                         --sp;
11590                         ins->sreg1 = sp [0]->dreg;
11591                         ip++;
11592                         cfg->cbb->out_of_line = TRUE;
11593                         MONO_ADD_INS (cfg->cbb, ins);
11594                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
11595                         MONO_ADD_INS (cfg->cbb, ins);
11596                         sp = stack_start;
11597                         
11598                         link_bblock (cfg, cfg->cbb, end_bblock);
11599                         start_new_bblock = 1;
11600                         /* This can complicate code generation for llvm since the return value might not be defined */
11601                         if (COMPILE_LLVM (cfg))
11602                                 INLINE_FAILURE ("throw");
11603                         break;
11604                 case CEE_ENDFINALLY:
11605                         if (!ip_in_finally_clause (cfg, ip - header->code))
11606                                 UNVERIFIED;
11607                         /* mono_save_seq_point_info () depends on this */
11608                         if (sp != stack_start)
11609                                 emit_seq_point (cfg, method, ip, FALSE, FALSE);
11610                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
11611                         MONO_ADD_INS (cfg->cbb, ins);
11612                         ip++;
11613                         start_new_bblock = 1;
11614
11615                         /*
11616                          * Control will leave the method so empty the stack, otherwise
11617                          * the next basic block will start with a nonempty stack.
11618                          */
11619                         while (sp != stack_start) {
11620                                 sp--;
11621                         }
11622                         break;
11623                 case CEE_LEAVE:
11624                 case CEE_LEAVE_S: {
11625                         GList *handlers;
11626
11627                         if (*ip == CEE_LEAVE) {
11628                                 CHECK_OPSIZE (5);
11629                                 target = ip + 5 + (gint32)read32(ip + 1);
11630                         } else {
11631                                 CHECK_OPSIZE (2);
11632                                 target = ip + 2 + (signed char)(ip [1]);
11633                         }
11634
11635                         /* empty the stack */
11636                         while (sp != stack_start) {
11637                                 sp--;
11638                         }
11639
11640                         /* 
11641                          * If this leave statement is in a catch block, check for a
11642                          * pending exception, and rethrow it if necessary.
11643                          * We avoid doing this in runtime invoke wrappers, since those are called
11644                          * by native code which excepts the wrapper to catch all exceptions.
11645                          */
11646                         for (i = 0; i < header->num_clauses; ++i) {
11647                                 MonoExceptionClause *clause = &header->clauses [i];
11648
11649                                 /* 
11650                                  * Use <= in the final comparison to handle clauses with multiple
11651                                  * leave statements, like in bug #78024.
11652                                  * The ordering of the exception clauses guarantees that we find the
11653                                  * innermost clause.
11654                                  */
11655                                 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) {
11656                                         MonoInst *exc_ins;
11657                                         MonoBasicBlock *dont_throw;
11658
11659                                         /*
11660                                           MonoInst *load;
11661
11662                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
11663                                         */
11664
11665                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
11666
11667                                         NEW_BBLOCK (cfg, dont_throw);
11668
11669                                         /*
11670                                          * Currently, we always rethrow the abort exception, despite the 
11671                                          * fact that this is not correct. See thread6.cs for an example. 
11672                                          * But propagating the abort exception is more important than 
11673                                          * getting the sematics right.
11674                                          */
11675                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
11676                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
11677                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
11678
11679                                         MONO_START_BB (cfg, dont_throw);
11680                                 }
11681                         }
11682
11683 #ifdef ENABLE_LLVM
11684                         cfg->cbb->try_end = (intptr_t)(ip - header->code);
11685 #endif
11686
11687                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
11688                                 GList *tmp;
11689                                 MonoExceptionClause *clause;
11690
11691                                 for (tmp = handlers; tmp; tmp = tmp->next) {
11692                                         clause = (MonoExceptionClause *)tmp->data;
11693                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
11694                                         g_assert (tblock);
11695                                         link_bblock (cfg, cfg->cbb, tblock);
11696                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
11697                                         ins->inst_target_bb = tblock;
11698                                         ins->inst_eh_block = clause;
11699                                         MONO_ADD_INS (cfg->cbb, ins);
11700                                         cfg->cbb->has_call_handler = 1;
11701                                         if (COMPILE_LLVM (cfg)) {
11702                                                 MonoBasicBlock *target_bb;
11703
11704                                                 /* 
11705                                                  * Link the finally bblock with the target, since it will
11706                                                  * conceptually branch there.
11707                                                  */
11708                                                 GET_BBLOCK (cfg, tblock, cfg->cil_start + clause->handler_offset + clause->handler_len - 1);
11709                                                 GET_BBLOCK (cfg, target_bb, target);
11710                                                 link_bblock (cfg, tblock, target_bb);
11711                                         }
11712                                 }
11713                                 g_list_free (handlers);
11714                         } 
11715
11716                         MONO_INST_NEW (cfg, ins, OP_BR);
11717                         MONO_ADD_INS (cfg->cbb, ins);
11718                         GET_BBLOCK (cfg, tblock, target);
11719                         link_bblock (cfg, cfg->cbb, tblock);
11720                         ins->inst_target_bb = tblock;
11721
11722                         start_new_bblock = 1;
11723
11724                         if (*ip == CEE_LEAVE)
11725                                 ip += 5;
11726                         else
11727                                 ip += 2;
11728
11729                         break;
11730                 }
11731
11732                         /*
11733                          * Mono specific opcodes
11734                          */
11735                 case MONO_CUSTOM_PREFIX: {
11736
11737                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
11738
11739                         CHECK_OPSIZE (2);
11740                         switch (ip [1]) {
11741                         case CEE_MONO_ICALL: {
11742                                 gpointer func;
11743                                 MonoJitICallInfo *info;
11744
11745                                 token = read32 (ip + 2);
11746                                 func = mono_method_get_wrapper_data (method, token);
11747                                 info = mono_find_jit_icall_by_addr (func);
11748                                 if (!info)
11749                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
11750                                 g_assert (info);
11751
11752                                 CHECK_STACK (info->sig->param_count);
11753                                 sp -= info->sig->param_count;
11754
11755                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
11756                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
11757                                         *sp++ = ins;
11758
11759                                 ip += 6;
11760                                 inline_costs += 10 * num_calls++;
11761
11762                                 break;
11763                         }
11764                         case CEE_MONO_LDPTR_CARD_TABLE:
11765                         case CEE_MONO_LDPTR_NURSERY_START:
11766                         case CEE_MONO_LDPTR_NURSERY_BITS:
11767                         case CEE_MONO_LDPTR_INT_REQ_FLAG: {
11768                                 CHECK_STACK_OVF (1);
11769
11770                                 switch (ip [1]) {
11771                                         case CEE_MONO_LDPTR_CARD_TABLE:
11772                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
11773                                                 break;
11774                                         case CEE_MONO_LDPTR_NURSERY_START:
11775                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_START, NULL);
11776                                                 break;
11777                                         case CEE_MONO_LDPTR_NURSERY_BITS:
11778                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_BITS, NULL);
11779                                                 break;
11780                                         case CEE_MONO_LDPTR_INT_REQ_FLAG:
11781                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
11782                                                 break;
11783                                 }
11784
11785                                 *sp++ = ins;
11786                                 ip += 2;
11787                                 inline_costs += 10 * num_calls++;
11788                                 break;
11789                         }
11790                         case CEE_MONO_LDPTR: {
11791                                 gpointer ptr;
11792
11793                                 CHECK_STACK_OVF (1);
11794                                 CHECK_OPSIZE (6);
11795                                 token = read32 (ip + 2);
11796
11797                                 ptr = mono_method_get_wrapper_data (method, token);
11798                                 EMIT_NEW_PCONST (cfg, ins, ptr);
11799                                 *sp++ = ins;
11800                                 ip += 6;
11801                                 inline_costs += 10 * num_calls++;
11802                                 /* Can't embed random pointers into AOT code */
11803                                 DISABLE_AOT (cfg);
11804                                 break;
11805                         }
11806                         case CEE_MONO_JIT_ICALL_ADDR: {
11807                                 MonoJitICallInfo *callinfo;
11808                                 gpointer ptr;
11809
11810                                 CHECK_STACK_OVF (1);
11811                                 CHECK_OPSIZE (6);
11812                                 token = read32 (ip + 2);
11813
11814                                 ptr = mono_method_get_wrapper_data (method, token);
11815                                 callinfo = mono_find_jit_icall_by_addr (ptr);
11816                                 g_assert (callinfo);
11817                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
11818                                 *sp++ = ins;
11819                                 ip += 6;
11820                                 inline_costs += 10 * num_calls++;
11821                                 break;
11822                         }
11823                         case CEE_MONO_ICALL_ADDR: {
11824                                 MonoMethod *cmethod;
11825                                 gpointer ptr;
11826
11827                                 CHECK_STACK_OVF (1);
11828                                 CHECK_OPSIZE (6);
11829                                 token = read32 (ip + 2);
11830
11831                                 cmethod = (MonoMethod *)mono_method_get_wrapper_data (method, token);
11832
11833                                 if (cfg->compile_aot) {
11834                                         if (cfg->direct_pinvoke && ip + 6 < end && (ip [6] == CEE_POP)) {
11835                                                 /*
11836                                                  * This is generated by emit_native_wrapper () to resolve the pinvoke address
11837                                                  * before the call, its not needed when using direct pinvoke.
11838                                                  * This is not an optimization, but its used to avoid looking up pinvokes
11839                                                  * on platforms which don't support dlopen ().
11840                                                  */
11841                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11842                                         } else {
11843                                                 EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
11844                                         }
11845                                 } else {
11846                                         ptr = mono_lookup_internal_call (cmethod);
11847                                         g_assert (ptr);
11848                                         EMIT_NEW_PCONST (cfg, ins, ptr);
11849                                 }
11850                                 *sp++ = ins;
11851                                 ip += 6;
11852                                 break;
11853                         }
11854                         case CEE_MONO_VTADDR: {
11855                                 MonoInst *src_var, *src;
11856
11857                                 CHECK_STACK (1);
11858                                 --sp;
11859
11860                                 // FIXME:
11861                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11862                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
11863                                 *sp++ = src;
11864                                 ip += 2;
11865                                 break;
11866                         }
11867                         case CEE_MONO_NEWOBJ: {
11868                                 MonoInst *iargs [2];
11869
11870                                 CHECK_STACK_OVF (1);
11871                                 CHECK_OPSIZE (6);
11872                                 token = read32 (ip + 2);
11873                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11874                                 mono_class_init (klass);
11875                                 NEW_DOMAINCONST (cfg, iargs [0]);
11876                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
11877                                 NEW_CLASSCONST (cfg, iargs [1], klass);
11878                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
11879                                 *sp++ = mono_emit_jit_icall (cfg, ves_icall_object_new, iargs);
11880                                 ip += 6;
11881                                 inline_costs += 10 * num_calls++;
11882                                 break;
11883                         }
11884                         case CEE_MONO_OBJADDR:
11885                                 CHECK_STACK (1);
11886                                 --sp;
11887                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
11888                                 ins->dreg = alloc_ireg_mp (cfg);
11889                                 ins->sreg1 = sp [0]->dreg;
11890                                 ins->type = STACK_MP;
11891                                 MONO_ADD_INS (cfg->cbb, ins);
11892                                 *sp++ = ins;
11893                                 ip += 2;
11894                                 break;
11895                         case CEE_MONO_LDNATIVEOBJ:
11896                                 /*
11897                                  * Similar to LDOBJ, but instead load the unmanaged 
11898                                  * representation of the vtype to the stack.
11899                                  */
11900                                 CHECK_STACK (1);
11901                                 CHECK_OPSIZE (6);
11902                                 --sp;
11903                                 token = read32 (ip + 2);
11904                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11905                                 g_assert (klass->valuetype);
11906                                 mono_class_init (klass);
11907
11908                                 {
11909                                         MonoInst *src, *dest, *temp;
11910
11911                                         src = sp [0];
11912                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
11913                                         temp->backend.is_pinvoke = 1;
11914                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
11915                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
11916
11917                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
11918                                         dest->type = STACK_VTYPE;
11919                                         dest->klass = klass;
11920
11921                                         *sp ++ = dest;
11922                                         ip += 6;
11923                                 }
11924                                 break;
11925                         case CEE_MONO_RETOBJ: {
11926                                 /*
11927                                  * Same as RET, but return the native representation of a vtype
11928                                  * to the caller.
11929                                  */
11930                                 g_assert (cfg->ret);
11931                                 g_assert (mono_method_signature (method)->pinvoke); 
11932                                 CHECK_STACK (1);
11933                                 --sp;
11934                                 
11935                                 CHECK_OPSIZE (6);
11936                                 token = read32 (ip + 2);    
11937                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11938
11939                                 if (!cfg->vret_addr) {
11940                                         g_assert (cfg->ret_var_is_local);
11941
11942                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
11943                                 } else {
11944                                         EMIT_NEW_RETLOADA (cfg, ins);
11945                                 }
11946                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
11947                                 
11948                                 if (sp != stack_start)
11949                                         UNVERIFIED;
11950                                 
11951                                 MONO_INST_NEW (cfg, ins, OP_BR);
11952                                 ins->inst_target_bb = end_bblock;
11953                                 MONO_ADD_INS (cfg->cbb, ins);
11954                                 link_bblock (cfg, cfg->cbb, end_bblock);
11955                                 start_new_bblock = 1;
11956                                 ip += 6;
11957                                 break;
11958                         }
11959                         case CEE_MONO_SAVE_LMF:
11960                         case CEE_MONO_RESTORE_LMF:
11961                                 ip += 2;
11962                                 break;
11963                         case CEE_MONO_CLASSCONST:
11964                                 CHECK_STACK_OVF (1);
11965                                 CHECK_OPSIZE (6);
11966                                 token = read32 (ip + 2);
11967                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
11968                                 *sp++ = ins;
11969                                 ip += 6;
11970                                 inline_costs += 10 * num_calls++;
11971                                 break;
11972                         case CEE_MONO_NOT_TAKEN:
11973                                 cfg->cbb->out_of_line = TRUE;
11974                                 ip += 2;
11975                                 break;
11976                         case CEE_MONO_TLS: {
11977                                 MonoTlsKey key;
11978
11979                                 CHECK_STACK_OVF (1);
11980                                 CHECK_OPSIZE (6);
11981                                 key = (MonoTlsKey)read32 (ip + 2);
11982                                 g_assert (key < TLS_KEY_NUM);
11983
11984                                 ins = mono_create_tls_get (cfg, key);
11985                                 if (!ins) {
11986                                         if (cfg->compile_aot) {
11987                                                 DISABLE_AOT (cfg);
11988                                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
11989                                                 ins->dreg = alloc_preg (cfg);
11990                                                 ins->type = STACK_PTR;
11991                                         } else {
11992                                                 g_assert_not_reached ();
11993                                         }
11994                                 }
11995                                 ins->type = STACK_PTR;
11996                                 MONO_ADD_INS (cfg->cbb, ins);
11997                                 *sp++ = ins;
11998                                 ip += 6;
11999                                 break;
12000                         }
12001                         case CEE_MONO_DYN_CALL: {
12002                                 MonoCallInst *call;
12003
12004                                 /* It would be easier to call a trampoline, but that would put an
12005                                  * extra frame on the stack, confusing exception handling. So
12006                                  * implement it inline using an opcode for now.
12007                                  */
12008
12009                                 if (!cfg->dyn_call_var) {
12010                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12011                                         /* prevent it from being register allocated */
12012                                         cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
12013                                 }
12014
12015                                 /* Has to use a call inst since it local regalloc expects it */
12016                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
12017                                 ins = (MonoInst*)call;
12018                                 sp -= 2;
12019                                 ins->sreg1 = sp [0]->dreg;
12020                                 ins->sreg2 = sp [1]->dreg;
12021                                 MONO_ADD_INS (cfg->cbb, ins);
12022
12023                                 cfg->param_area = MAX (cfg->param_area, cfg->backend->dyn_call_param_area);
12024
12025                                 ip += 2;
12026                                 inline_costs += 10 * num_calls++;
12027
12028                                 break;
12029                         }
12030                         case CEE_MONO_MEMORY_BARRIER: {
12031                                 CHECK_OPSIZE (6);
12032                                 emit_memory_barrier (cfg, (int)read32 (ip + 2));
12033                                 ip += 6;
12034                                 break;
12035                         }
12036                         case CEE_MONO_ATOMIC_STORE_I4: {
12037                                 g_assert (mono_arch_opcode_supported (OP_ATOMIC_STORE_I4));
12038
12039                                 CHECK_OPSIZE (6);
12040                                 CHECK_STACK (2);
12041                                 sp -= 2;
12042
12043                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_STORE_I4);
12044                                 ins->dreg = sp [0]->dreg;
12045                                 ins->sreg1 = sp [1]->dreg;
12046                                 ins->backend.memory_barrier_kind = (int) read32 (ip + 2);
12047                                 MONO_ADD_INS (cfg->cbb, ins);
12048
12049                                 ip += 6;
12050                                 break;
12051                         }
12052                         case CEE_MONO_JIT_ATTACH: {
12053                                 MonoInst *args [16], *domain_ins;
12054                                 MonoInst *ad_ins, *jit_tls_ins;
12055                                 MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
12056
12057                                 g_assert (!mono_threads_is_coop_enabled ());
12058
12059                                 cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12060
12061                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12062                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12063
12064                                 ad_ins = mono_get_domain_intrinsic (cfg);
12065                                 jit_tls_ins = mono_get_jit_tls_intrinsic (cfg);
12066
12067                                 if (cfg->backend->have_tls_get && ad_ins && jit_tls_ins) {
12068                                         NEW_BBLOCK (cfg, next_bb);
12069                                         NEW_BBLOCK (cfg, call_bb);
12070
12071                                         if (cfg->compile_aot) {
12072                                                 /* AOT code is only used in the root domain */
12073                                                 EMIT_NEW_PCONST (cfg, domain_ins, NULL);
12074                                         } else {
12075                                                 EMIT_NEW_PCONST (cfg, domain_ins, cfg->domain);
12076                                         }
12077                                         MONO_ADD_INS (cfg->cbb, ad_ins);
12078                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg);
12079                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb);
12080
12081                                         MONO_ADD_INS (cfg->cbb, jit_tls_ins);
12082                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0);
12083                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb);
12084
12085                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb);
12086                                         MONO_START_BB (cfg, call_bb);
12087                                 }
12088
12089                                 /* AOT code is only used in the root domain */
12090                                 EMIT_NEW_PCONST (cfg, args [0], cfg->compile_aot ? NULL : cfg->domain);
12091                                 ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
12092                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12093
12094                                 if (next_bb)
12095                                         MONO_START_BB (cfg, next_bb);
12096
12097
12098                                 ip += 2;
12099                                 break;
12100                         }
12101                         case CEE_MONO_JIT_DETACH: {
12102                                 MonoInst *args [16];
12103
12104                                 /* Restore the original domain */
12105                                 dreg = alloc_ireg (cfg);
12106                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->orig_domain_var->dreg);
12107                                 mono_emit_jit_icall (cfg, mono_jit_set_domain, args);
12108                                 ip += 2;
12109                                 break;
12110                         }
12111                         case CEE_MONO_CALLI_EXTRA_ARG: {
12112                                 MonoInst *addr;
12113                                 MonoMethodSignature *fsig;
12114                                 MonoInst *arg;
12115
12116                                 /*
12117                                  * This is the same as CEE_CALLI, but passes an additional argument
12118                                  * to the called method in llvmonly mode.
12119                                  * This is only used by delegate invoke wrappers to call the
12120                                  * actual delegate method.
12121                                  */
12122                                 g_assert (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE);
12123
12124                                 CHECK_OPSIZE (6);
12125                                 token = read32 (ip + 2);
12126
12127                                 ins = NULL;
12128
12129                                 cmethod = NULL;
12130                                 CHECK_STACK (1);
12131                                 --sp;
12132                                 addr = *sp;
12133                                 fsig = mini_get_signature (method, token, generic_context, &cfg->error);
12134                                 CHECK_CFG_ERROR;
12135
12136                                 if (cfg->llvm_only)
12137                                         cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
12138
12139                                 n = fsig->param_count + fsig->hasthis + 1;
12140
12141                                 CHECK_STACK (n);
12142
12143                                 sp -= n;
12144                                 arg = sp [n - 1];
12145
12146                                 if (cfg->llvm_only) {
12147                                         /*
12148                                          * The lowest bit of 'arg' determines whenever the callee uses the gsharedvt
12149                                          * cconv. This is set by mono_init_delegate ().
12150                                          */
12151                                         if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig)) {
12152                                                 MonoInst *callee = addr;
12153                                                 MonoInst *call, *localloc_ins;
12154                                                 MonoBasicBlock *is_gsharedvt_bb, *end_bb;
12155                                                 int low_bit_reg = alloc_preg (cfg);
12156
12157                                                 NEW_BBLOCK (cfg, is_gsharedvt_bb);
12158                                                 NEW_BBLOCK (cfg, end_bb);
12159
12160                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
12161                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
12162                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
12163
12164                                                 /* Normal case: callee uses a normal cconv, have to add an out wrapper */
12165                                                 addr = emit_get_rgctx_sig (cfg, context_used,
12166                                                                                                    fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
12167                                                 /*
12168                                                  * ADDR points to a gsharedvt-out wrapper, have to pass <callee, arg> as an extra arg.
12169                                                  */
12170                                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
12171                                                 ins->dreg = alloc_preg (cfg);
12172                                                 ins->inst_imm = 2 * SIZEOF_VOID_P;
12173                                                 MONO_ADD_INS (cfg->cbb, ins);
12174                                                 localloc_ins = ins;
12175                                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12176                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
12177                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
12178
12179                                                 call = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
12180                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12181
12182                                                 /* Gsharedvt case: callee uses a gsharedvt cconv, no conversion is needed */
12183                                                 MONO_START_BB (cfg, is_gsharedvt_bb);
12184                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
12185                                                 ins = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
12186                                                 ins->dreg = call->dreg;
12187
12188                                                 MONO_START_BB (cfg, end_bb);
12189                                         } else {
12190                                                 /* Caller uses a normal calling conv */
12191
12192                                                 MonoInst *callee = addr;
12193                                                 MonoInst *call, *localloc_ins;
12194                                                 MonoBasicBlock *is_gsharedvt_bb, *end_bb;
12195                                                 int low_bit_reg = alloc_preg (cfg);
12196
12197                                                 NEW_BBLOCK (cfg, is_gsharedvt_bb);
12198                                                 NEW_BBLOCK (cfg, end_bb);
12199
12200                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
12201                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
12202                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
12203
12204                                                 /* Normal case: callee uses a normal cconv, no conversion is needed */
12205                                                 call = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
12206                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12207                                                 /* Gsharedvt case: callee uses a gsharedvt cconv, have to add an in wrapper */
12208                                                 MONO_START_BB (cfg, is_gsharedvt_bb);
12209                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
12210                                                 NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER, fsig);
12211                                                 MONO_ADD_INS (cfg->cbb, addr);
12212                                                 /*
12213                                                  * ADDR points to a gsharedvt-in wrapper, have to pass <callee, arg> as an extra arg.
12214                                                  */
12215                                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
12216                                                 ins->dreg = alloc_preg (cfg);
12217                                                 ins->inst_imm = 2 * SIZEOF_VOID_P;
12218                                                 MONO_ADD_INS (cfg->cbb, ins);
12219                                                 localloc_ins = ins;
12220                                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12221                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
12222                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
12223
12224                                                 ins = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
12225                                                 ins->dreg = call->dreg;
12226                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12227
12228                                                 MONO_START_BB (cfg, end_bb);
12229                                         }
12230                                 } else {
12231                                         /* Same as CEE_CALLI */
12232                                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
12233                                                 /*
12234                                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
12235                                                  */
12236                                                 MonoInst *callee = addr;
12237
12238                                                 addr = emit_get_rgctx_sig (cfg, context_used,
12239                                                                                                    fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
12240                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
12241                                         } else {
12242                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
12243                                         }
12244                                 }
12245
12246                                 if (!MONO_TYPE_IS_VOID (fsig->ret))
12247                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
12248
12249                                 CHECK_CFG_EXCEPTION;
12250
12251                                 ip += 6;
12252                                 ins_flag = 0;
12253                                 constrained_class = NULL;
12254                                 break;
12255                         }
12256                         case CEE_MONO_LDDOMAIN:
12257                                 CHECK_STACK_OVF (1);
12258                                 EMIT_NEW_PCONST (cfg, ins, cfg->compile_aot ? NULL : cfg->domain);
12259                                 ip += 2;
12260                                 *sp++ = ins;
12261                                 break;
12262                         case CEE_MONO_GET_LAST_ERROR:
12263                                 CHECK_OPSIZE (2);
12264                                 CHECK_STACK_OVF (1);
12265
12266                                 MONO_INST_NEW (cfg, ins, OP_GET_LAST_ERROR);
12267                                 ins->dreg = alloc_dreg (cfg, STACK_I4);
12268                                 ins->type = STACK_I4;
12269                                 MONO_ADD_INS (cfg->cbb, ins);
12270
12271                                 ip += 2;
12272                                 *sp++ = ins;
12273                                 break;
12274                         default:
12275                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
12276                                 break;
12277                         }
12278                         break;
12279                 }
12280
12281                 case CEE_PREFIX1: {
12282                         CHECK_OPSIZE (2);
12283                         switch (ip [1]) {
12284                         case CEE_ARGLIST: {
12285                                 /* somewhat similar to LDTOKEN */
12286                                 MonoInst *addr, *vtvar;
12287                                 CHECK_STACK_OVF (1);
12288                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
12289
12290                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12291                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
12292
12293                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12294                                 ins->type = STACK_VTYPE;
12295                                 ins->klass = mono_defaults.argumenthandle_class;
12296                                 *sp++ = ins;
12297                                 ip += 2;
12298                                 break;
12299                         }
12300                         case CEE_CEQ:
12301                         case CEE_CGT:
12302                         case CEE_CGT_UN:
12303                         case CEE_CLT:
12304                         case CEE_CLT_UN: {
12305                                 MonoInst *cmp, *arg1, *arg2;
12306
12307                                 CHECK_STACK (2);
12308                                 sp -= 2;
12309                                 arg1 = sp [0];
12310                                 arg2 = sp [1];
12311
12312                                 /*
12313                                  * The following transforms:
12314                                  *    CEE_CEQ    into OP_CEQ
12315                                  *    CEE_CGT    into OP_CGT
12316                                  *    CEE_CGT_UN into OP_CGT_UN
12317                                  *    CEE_CLT    into OP_CLT
12318                                  *    CEE_CLT_UN into OP_CLT_UN
12319                                  */
12320                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
12321
12322                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
12323                                 cmp->sreg1 = arg1->dreg;
12324                                 cmp->sreg2 = arg2->dreg;
12325                                 type_from_op (cfg, cmp, arg1, arg2);
12326                                 CHECK_TYPE (cmp);
12327                                 add_widen_op (cfg, cmp, &arg1, &arg2);
12328                                 if ((arg1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((arg1->type == STACK_PTR) || (arg1->type == STACK_OBJ) || (arg1->type == STACK_MP))))
12329                                         cmp->opcode = OP_LCOMPARE;
12330                                 else if (arg1->type == STACK_R4)
12331                                         cmp->opcode = OP_RCOMPARE;
12332                                 else if (arg1->type == STACK_R8)
12333                                         cmp->opcode = OP_FCOMPARE;
12334                                 else
12335                                         cmp->opcode = OP_ICOMPARE;
12336                                 MONO_ADD_INS (cfg->cbb, cmp);
12337                                 ins->type = STACK_I4;
12338                                 ins->dreg = alloc_dreg (cfg, (MonoStackType)ins->type);
12339                                 type_from_op (cfg, ins, arg1, arg2);
12340
12341                                 if (cmp->opcode == OP_FCOMPARE || cmp->opcode == OP_RCOMPARE) {
12342                                         /*
12343                                          * The backends expect the fceq opcodes to do the
12344                                          * comparison too.
12345                                          */
12346                                         ins->sreg1 = cmp->sreg1;
12347                                         ins->sreg2 = cmp->sreg2;
12348                                         NULLIFY_INS (cmp);
12349                                 }
12350                                 MONO_ADD_INS (cfg->cbb, ins);
12351                                 *sp++ = ins;
12352                                 ip += 2;
12353                                 break;
12354                         }
12355                         case CEE_LDFTN: {
12356                                 MonoInst *argconst;
12357                                 MonoMethod *cil_method;
12358
12359                                 CHECK_STACK_OVF (1);
12360                                 CHECK_OPSIZE (6);
12361                                 n = read32 (ip + 2);
12362                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12363                                 CHECK_CFG_ERROR;
12364
12365                                 mono_class_init (cmethod->klass);
12366
12367                                 mono_save_token_info (cfg, image, n, cmethod);
12368
12369                                 context_used = mini_method_check_context_used (cfg, cmethod);
12370
12371                                 cil_method = cmethod;
12372                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
12373                                         emit_method_access_failure (cfg, method, cil_method);
12374
12375                                 if (mono_security_core_clr_enabled ())
12376                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
12377
12378                                 /* 
12379                                  * Optimize the common case of ldftn+delegate creation
12380                                  */
12381                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
12382                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12383                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12384                                                 MonoInst *target_ins, *handle_ins;
12385                                                 MonoMethod *invoke;
12386                                                 int invoke_context_used;
12387
12388                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12389                                                 if (!invoke || !mono_method_signature (invoke))
12390                                                         LOAD_ERROR;
12391
12392                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12393
12394                                                 target_ins = sp [-1];
12395
12396                                                 if (mono_security_core_clr_enabled ())
12397                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
12398
12399                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
12400                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
12401                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
12402                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
12403                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
12404                                                         }
12405                                                 }
12406
12407                                                 /* FIXME: SGEN support */
12408                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
12409                                                         ip += 6;
12410                                                         if (cfg->verbose_level > 3)
12411                                                                 g_print ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
12412                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, FALSE))) {
12413                                                                 sp --;
12414                                                                 *sp = handle_ins;
12415                                                                 CHECK_CFG_EXCEPTION;
12416                                                                 ip += 5;
12417                                                                 sp ++;
12418                                                                 break;
12419                                                         }
12420                                                         ip -= 6;
12421                                                 }
12422                                         }
12423                                 }
12424
12425                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
12426                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
12427                                 *sp++ = ins;
12428                                 
12429                                 ip += 6;
12430                                 inline_costs += 10 * num_calls++;
12431                                 break;
12432                         }
12433                         case CEE_LDVIRTFTN: {
12434                                 MonoInst *args [2];
12435
12436                                 CHECK_STACK (1);
12437                                 CHECK_OPSIZE (6);
12438                                 n = read32 (ip + 2);
12439                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12440                                 CHECK_CFG_ERROR;
12441
12442                                 mono_class_init (cmethod->klass);
12443  
12444                                 context_used = mini_method_check_context_used (cfg, cmethod);
12445
12446                                 if (mono_security_core_clr_enabled ())
12447                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
12448
12449                                 /*
12450                                  * Optimize the common case of ldvirtftn+delegate creation
12451                                  */
12452                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 6) && (ip [6] == CEE_NEWOBJ) && (ip > header->code && ip [-1] == CEE_DUP)) {
12453                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12454                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12455                                                 MonoInst *target_ins, *handle_ins;
12456                                                 MonoMethod *invoke;
12457                                                 int invoke_context_used;
12458                                                 gboolean is_virtual = cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL;
12459
12460                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12461                                                 if (!invoke || !mono_method_signature (invoke))
12462                                                         LOAD_ERROR;
12463
12464                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12465
12466                                                 target_ins = sp [-1];
12467
12468                                                 if (mono_security_core_clr_enabled ())
12469                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
12470
12471                                                 /* FIXME: SGEN support */
12472                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
12473                                                         ip += 6;
12474                                                         if (cfg->verbose_level > 3)
12475                                                                 g_print ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
12476                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, is_virtual))) {
12477                                                                 sp -= 2;
12478                                                                 *sp = handle_ins;
12479                                                                 CHECK_CFG_EXCEPTION;
12480                                                                 ip += 5;
12481                                                                 sp ++;
12482                                                                 break;
12483                                                         }
12484                                                         ip -= 6;
12485                                                 }
12486                                         }
12487                                 }
12488
12489                                 --sp;
12490                                 args [0] = *sp;
12491
12492                                 args [1] = emit_get_rgctx_method (cfg, context_used,
12493                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
12494
12495                                 if (context_used)
12496                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
12497                                 else
12498                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
12499
12500                                 ip += 6;
12501                                 inline_costs += 10 * num_calls++;
12502                                 break;
12503                         }
12504                         case CEE_LDARG:
12505                                 CHECK_STACK_OVF (1);
12506                                 CHECK_OPSIZE (4);
12507                                 n = read16 (ip + 2);
12508                                 CHECK_ARG (n);
12509                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
12510                                 *sp++ = ins;
12511                                 ip += 4;
12512                                 break;
12513                         case CEE_LDARGA:
12514                                 CHECK_STACK_OVF (1);
12515                                 CHECK_OPSIZE (4);
12516                                 n = read16 (ip + 2);
12517                                 CHECK_ARG (n);
12518                                 NEW_ARGLOADA (cfg, ins, n);
12519                                 MONO_ADD_INS (cfg->cbb, ins);
12520                                 *sp++ = ins;
12521                                 ip += 4;
12522                                 break;
12523                         case CEE_STARG:
12524                                 CHECK_STACK (1);
12525                                 --sp;
12526                                 CHECK_OPSIZE (4);
12527                                 n = read16 (ip + 2);
12528                                 CHECK_ARG (n);
12529                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
12530                                         UNVERIFIED;
12531                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
12532                                 ip += 4;
12533                                 break;
12534                         case CEE_LDLOC:
12535                                 CHECK_STACK_OVF (1);
12536                                 CHECK_OPSIZE (4);
12537                                 n = read16 (ip + 2);
12538                                 CHECK_LOCAL (n);
12539                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
12540                                 *sp++ = ins;
12541                                 ip += 4;
12542                                 break;
12543                         case CEE_LDLOCA: {
12544                                 unsigned char *tmp_ip;
12545                                 CHECK_STACK_OVF (1);
12546                                 CHECK_OPSIZE (4);
12547                                 n = read16 (ip + 2);
12548                                 CHECK_LOCAL (n);
12549
12550                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
12551                                         ip = tmp_ip;
12552                                         inline_costs += 1;
12553                                         break;
12554                                 }                       
12555                                 
12556                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
12557                                 *sp++ = ins;
12558                                 ip += 4;
12559                                 break;
12560                         }
12561                         case CEE_STLOC:
12562                                 CHECK_STACK (1);
12563                                 --sp;
12564                                 CHECK_OPSIZE (4);
12565                                 n = read16 (ip + 2);
12566                                 CHECK_LOCAL (n);
12567                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
12568                                         UNVERIFIED;
12569                                 emit_stloc_ir (cfg, sp, header, n);
12570                                 ip += 4;
12571                                 inline_costs += 1;
12572                                 break;
12573                         case CEE_LOCALLOC: {
12574                                 CHECK_STACK (1);
12575                                 MonoBasicBlock *non_zero_bb, *end_bb;
12576                                 int alloc_ptr = alloc_preg (cfg);
12577                                 --sp;
12578                                 if (sp != stack_start) 
12579                                         UNVERIFIED;
12580                                 if (cfg->method != method) 
12581                                         /* 
12582                                          * Inlining this into a loop in a parent could lead to 
12583                                          * stack overflows which is different behavior than the
12584                                          * non-inlined case, thus disable inlining in this case.
12585                                          */
12586                                         INLINE_FAILURE("localloc");
12587
12588                                 NEW_BBLOCK (cfg, non_zero_bb);
12589                                 NEW_BBLOCK (cfg, end_bb);
12590
12591                                 /* if size != zero */
12592                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
12593                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, non_zero_bb);
12594
12595                                 //size is zero, so result is NULL
12596                                 MONO_EMIT_NEW_PCONST (cfg, alloc_ptr, NULL);
12597                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12598
12599                                 MONO_START_BB (cfg, non_zero_bb);
12600                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
12601                                 ins->dreg = alloc_ptr;
12602                                 ins->sreg1 = sp [0]->dreg;
12603                                 ins->type = STACK_PTR;
12604                                 MONO_ADD_INS (cfg->cbb, ins);
12605
12606                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12607                                 if (init_locals)
12608                                         ins->flags |= MONO_INST_INIT;
12609
12610                                 MONO_START_BB (cfg, end_bb);
12611                                 EMIT_NEW_UNALU (cfg, ins, OP_MOVE, alloc_preg (cfg), alloc_ptr);
12612                                 ins->type = STACK_PTR;
12613
12614                                 *sp++ = ins;
12615                                 ip += 2;
12616                                 break;
12617                         }
12618                         case CEE_ENDFILTER: {
12619                                 MonoExceptionClause *clause, *nearest;
12620                                 int cc;
12621
12622                                 CHECK_STACK (1);
12623                                 --sp;
12624                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
12625                                         UNVERIFIED;
12626                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
12627                                 ins->sreg1 = (*sp)->dreg;
12628                                 MONO_ADD_INS (cfg->cbb, ins);
12629                                 start_new_bblock = 1;
12630                                 ip += 2;
12631
12632                                 nearest = NULL;
12633                                 for (cc = 0; cc < header->num_clauses; ++cc) {
12634                                         clause = &header->clauses [cc];
12635                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
12636                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
12637                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset)))
12638                                                 nearest = clause;
12639                                 }
12640                                 g_assert (nearest);
12641                                 if ((ip - header->code) != nearest->handler_offset)
12642                                         UNVERIFIED;
12643
12644                                 break;
12645                         }
12646                         case CEE_UNALIGNED_:
12647                                 ins_flag |= MONO_INST_UNALIGNED;
12648                                 /* FIXME: record alignment? we can assume 1 for now */
12649                                 CHECK_OPSIZE (3);
12650                                 ip += 3;
12651                                 break;
12652                         case CEE_VOLATILE_:
12653                                 ins_flag |= MONO_INST_VOLATILE;
12654                                 ip += 2;
12655                                 break;
12656                         case CEE_TAIL_:
12657                                 ins_flag   |= MONO_INST_TAILCALL;
12658                                 cfg->flags |= MONO_CFG_HAS_TAIL;
12659                                 /* Can't inline tail calls at this time */
12660                                 inline_costs += 100000;
12661                                 ip += 2;
12662                                 break;
12663                         case CEE_INITOBJ:
12664                                 CHECK_STACK (1);
12665                                 --sp;
12666                                 CHECK_OPSIZE (6);
12667                                 token = read32 (ip + 2);
12668                                 klass = mini_get_class (method, token, generic_context);
12669                                 CHECK_TYPELOAD (klass);
12670                                 if (generic_class_is_reference_type (cfg, klass))
12671                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
12672                                 else
12673                                         mini_emit_initobj (cfg, *sp, NULL, klass);
12674                                 ip += 6;
12675                                 inline_costs += 1;
12676                                 break;
12677                         case CEE_CONSTRAINED_:
12678                                 CHECK_OPSIZE (6);
12679                                 token = read32 (ip + 2);
12680                                 constrained_class = mini_get_class (method, token, generic_context);
12681                                 CHECK_TYPELOAD (constrained_class);
12682                                 ip += 6;
12683                                 break;
12684                         case CEE_CPBLK:
12685                         case CEE_INITBLK: {
12686                                 MonoInst *iargs [3];
12687                                 CHECK_STACK (3);
12688                                 sp -= 3;
12689
12690                                 /* Skip optimized paths for volatile operations. */
12691                                 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)) {
12692                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
12693                                 } 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)) {
12694                                         /* emit_memset only works when val == 0 */
12695                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
12696                                 } else {
12697                                         MonoInst *call;
12698                                         iargs [0] = sp [0];
12699                                         iargs [1] = sp [1];
12700                                         iargs [2] = sp [2];
12701                                         if (ip [1] == CEE_CPBLK) {
12702                                                 /*
12703                                                  * FIXME: It's unclear whether we should be emitting both the acquire
12704                                                  * and release barriers for cpblk. It is technically both a load and
12705                                                  * store operation, so it seems like that's the sensible thing to do.
12706                                                  *
12707                                                  * FIXME: We emit full barriers on both sides of the operation for
12708                                                  * simplicity. We should have a separate atomic memcpy method instead.
12709                                                  */
12710                                                 MonoMethod *memcpy_method = get_memcpy_method ();
12711
12712                                                 if (ins_flag & MONO_INST_VOLATILE)
12713                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12714
12715                                                 call = mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
12716                                                 call->flags |= ins_flag;
12717
12718                                                 if (ins_flag & MONO_INST_VOLATILE)
12719                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12720                                         } else {
12721                                                 MonoMethod *memset_method = get_memset_method ();
12722                                                 if (ins_flag & MONO_INST_VOLATILE) {
12723                                                         /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
12724                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
12725                                                 }
12726                                                 call = mono_emit_method_call (cfg, memset_method, iargs, NULL);
12727                                                 call->flags |= ins_flag;
12728                                         }
12729                                 }
12730                                 ip += 2;
12731                                 ins_flag = 0;
12732                                 inline_costs += 1;
12733                                 break;
12734                         }
12735                         case CEE_NO_:
12736                                 CHECK_OPSIZE (3);
12737                                 if (ip [2] & 0x1)
12738                                         ins_flag |= MONO_INST_NOTYPECHECK;
12739                                 if (ip [2] & 0x2)
12740                                         ins_flag |= MONO_INST_NORANGECHECK;
12741                                 /* we ignore the no-nullcheck for now since we
12742                                  * really do it explicitly only when doing callvirt->call
12743                                  */
12744                                 ip += 3;
12745                                 break;
12746                         case CEE_RETHROW: {
12747                                 MonoInst *load;
12748                                 int handler_offset = -1;
12749
12750                                 for (i = 0; i < header->num_clauses; ++i) {
12751                                         MonoExceptionClause *clause = &header->clauses [i];
12752                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
12753                                                 handler_offset = clause->handler_offset;
12754                                                 break;
12755                                         }
12756                                 }
12757
12758                                 cfg->cbb->flags |= BB_EXCEPTION_UNSAFE;
12759
12760                                 if (handler_offset == -1)
12761                                         UNVERIFIED;
12762
12763                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
12764                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
12765                                 ins->sreg1 = load->dreg;
12766                                 MONO_ADD_INS (cfg->cbb, ins);
12767
12768                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
12769                                 MONO_ADD_INS (cfg->cbb, ins);
12770
12771                                 sp = stack_start;
12772                                 link_bblock (cfg, cfg->cbb, end_bblock);
12773                                 start_new_bblock = 1;
12774                                 ip += 2;
12775                                 break;
12776                         }
12777                         case CEE_SIZEOF: {
12778                                 guint32 val;
12779                                 int ialign;
12780
12781                                 CHECK_STACK_OVF (1);
12782                                 CHECK_OPSIZE (6);
12783                                 token = read32 (ip + 2);
12784                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !image_is_dynamic (method->klass->image) && !generic_context) {
12785                                         MonoType *type = mono_type_create_from_typespec_checked (image, token, &cfg->error);
12786                                         CHECK_CFG_ERROR;
12787
12788                                         val = mono_type_size (type, &ialign);
12789                                 } else {
12790                                         MonoClass *klass = mini_get_class (method, token, generic_context);
12791                                         CHECK_TYPELOAD (klass);
12792
12793                                         val = mono_type_size (&klass->byval_arg, &ialign);
12794
12795                                         if (mini_is_gsharedvt_klass (klass))
12796                                                 GSHAREDVT_FAILURE (*ip);
12797                                 }
12798                                 EMIT_NEW_ICONST (cfg, ins, val);
12799                                 *sp++= ins;
12800                                 ip += 6;
12801                                 break;
12802                         }
12803                         case CEE_REFANYTYPE: {
12804                                 MonoInst *src_var, *src;
12805
12806                                 GSHAREDVT_FAILURE (*ip);
12807
12808                                 CHECK_STACK (1);
12809                                 --sp;
12810
12811                                 // FIXME:
12812                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12813                                 if (!src_var)
12814                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
12815                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
12816                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type));
12817                                 *sp++ = ins;
12818                                 ip += 2;
12819                                 break;
12820                         }
12821                         case CEE_READONLY_:
12822                                 readonly = TRUE;
12823                                 ip += 2;
12824                                 break;
12825
12826                         case CEE_UNUSED56:
12827                         case CEE_UNUSED57:
12828                         case CEE_UNUSED70:
12829                         case CEE_UNUSED:
12830                         case CEE_UNUSED99:
12831                                 UNVERIFIED;
12832                                 
12833                         default:
12834                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
12835                                 UNVERIFIED;
12836                         }
12837                         break;
12838                 }
12839                 case CEE_UNUSED58:
12840                 case CEE_UNUSED1:
12841                         UNVERIFIED;
12842
12843                 default:
12844                         g_warning ("opcode 0x%02x not handled", *ip);
12845                         UNVERIFIED;
12846                 }
12847         }
12848         if (start_new_bblock != 1)
12849                 UNVERIFIED;
12850
12851         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
12852         if (cfg->cbb->next_bb) {
12853                 /* This could already be set because of inlining, #693905 */
12854                 MonoBasicBlock *bb = cfg->cbb;
12855
12856                 while (bb->next_bb)
12857                         bb = bb->next_bb;
12858                 bb->next_bb = end_bblock;
12859         } else {
12860                 cfg->cbb->next_bb = end_bblock;
12861         }
12862
12863         if (cfg->method == method && cfg->domainvar) {
12864                 MonoInst *store;
12865                 MonoInst *get_domain;
12866
12867                 cfg->cbb = init_localsbb;
12868
12869                 if ((get_domain = mono_get_domain_intrinsic (cfg))) {
12870                         MONO_ADD_INS (cfg->cbb, get_domain);
12871                 } else {
12872                         get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
12873                 }
12874                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
12875                 MONO_ADD_INS (cfg->cbb, store);
12876         }
12877
12878 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
12879         if (cfg->compile_aot)
12880                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
12881                 mono_get_got_var (cfg);
12882 #endif
12883
12884         if (cfg->method == method && cfg->got_var)
12885                 mono_emit_load_got_addr (cfg);
12886
12887         if (init_localsbb) {
12888                 cfg->cbb = init_localsbb;
12889                 cfg->ip = NULL;
12890                 for (i = 0; i < header->num_locals; ++i) {
12891                         emit_init_local (cfg, i, header->locals [i], init_locals);
12892                 }
12893         }
12894
12895         if (cfg->init_ref_vars && cfg->method == method) {
12896                 /* Emit initialization for ref vars */
12897                 // FIXME: Avoid duplication initialization for IL locals.
12898                 for (i = 0; i < cfg->num_varinfo; ++i) {
12899                         MonoInst *ins = cfg->varinfo [i];
12900
12901                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
12902                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
12903                 }
12904         }
12905
12906         if (cfg->lmf_var && cfg->method == method && !cfg->llvm_only) {
12907                 cfg->cbb = init_localsbb;
12908                 emit_push_lmf (cfg);
12909         }
12910
12911         cfg->cbb = init_localsbb;
12912         emit_instrumentation_call (cfg, mono_profiler_method_enter);
12913
12914         if (seq_points) {
12915                 MonoBasicBlock *bb;
12916
12917                 /*
12918                  * Make seq points at backward branch targets interruptable.
12919                  */
12920                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
12921                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
12922                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
12923         }
12924
12925         /* Add a sequence point for method entry/exit events */
12926         if (seq_points && cfg->gen_sdb_seq_points) {
12927                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
12928                 MONO_ADD_INS (init_localsbb, ins);
12929                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
12930                 MONO_ADD_INS (cfg->bb_exit, ins);
12931         }
12932
12933         /*
12934          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
12935          * the code they refer to was dead (#11880).
12936          */
12937         if (sym_seq_points) {
12938                 for (i = 0; i < header->code_size; ++i) {
12939                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
12940                                 MonoInst *ins;
12941
12942                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
12943                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
12944                         }
12945                 }
12946         }
12947
12948         cfg->ip = NULL;
12949
12950         if (cfg->method == method) {
12951                 MonoBasicBlock *bb;
12952                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12953                         if (bb == cfg->bb_init)
12954                                 bb->region = -1;
12955                         else
12956                                 bb->region = mono_find_block_region (cfg, bb->real_offset);
12957                         if (cfg->spvars)
12958                                 mono_create_spvar_for_region (cfg, bb->region);
12959                         if (cfg->verbose_level > 2)
12960                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
12961                 }
12962         } else {
12963                 MonoBasicBlock *bb;
12964                 /* get_most_deep_clause () in mini-llvm.c depends on this for inlined bblocks */
12965                 for (bb = start_bblock; bb != end_bblock; bb  = bb->next_bb) {
12966                         bb->real_offset = inline_offset;
12967                 }
12968         }
12969
12970         if (inline_costs < 0) {
12971                 char *mname;
12972
12973                 /* Method is too large */
12974                 mname = mono_method_full_name (method, TRUE);
12975                 mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Method %s is too complex.", mname));
12976                 g_free (mname);
12977         }
12978
12979         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
12980                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
12981
12982         goto cleanup;
12983
12984 mono_error_exit:
12985         g_assert (!mono_error_ok (&cfg->error));
12986         goto cleanup;
12987  
12988  exception_exit:
12989         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
12990         goto cleanup;
12991
12992  unverified:
12993         set_exception_type_from_invalid_il (cfg, method, ip);
12994         goto cleanup;
12995
12996  cleanup:
12997         g_slist_free (class_inits);
12998         mono_basic_block_free (original_bb);
12999         cfg->dont_inline = g_list_remove (cfg->dont_inline, method);
13000         if (cfg->exception_type)
13001                 return -1;
13002         else
13003                 return inline_costs;
13004 }
13005
13006 static int
13007 store_membase_reg_to_store_membase_imm (int opcode)
13008 {
13009         switch (opcode) {
13010         case OP_STORE_MEMBASE_REG:
13011                 return OP_STORE_MEMBASE_IMM;
13012         case OP_STOREI1_MEMBASE_REG:
13013                 return OP_STOREI1_MEMBASE_IMM;
13014         case OP_STOREI2_MEMBASE_REG:
13015                 return OP_STOREI2_MEMBASE_IMM;
13016         case OP_STOREI4_MEMBASE_REG:
13017                 return OP_STOREI4_MEMBASE_IMM;
13018         case OP_STOREI8_MEMBASE_REG:
13019                 return OP_STOREI8_MEMBASE_IMM;
13020         default:
13021                 g_assert_not_reached ();
13022         }
13023
13024         return -1;
13025 }               
13026
13027 int
13028 mono_op_to_op_imm (int opcode)
13029 {
13030         switch (opcode) {
13031         case OP_IADD:
13032                 return OP_IADD_IMM;
13033         case OP_ISUB:
13034                 return OP_ISUB_IMM;
13035         case OP_IDIV:
13036                 return OP_IDIV_IMM;
13037         case OP_IDIV_UN:
13038                 return OP_IDIV_UN_IMM;
13039         case OP_IREM:
13040                 return OP_IREM_IMM;
13041         case OP_IREM_UN:
13042                 return OP_IREM_UN_IMM;
13043         case OP_IMUL:
13044                 return OP_IMUL_IMM;
13045         case OP_IAND:
13046                 return OP_IAND_IMM;
13047         case OP_IOR:
13048                 return OP_IOR_IMM;
13049         case OP_IXOR:
13050                 return OP_IXOR_IMM;
13051         case OP_ISHL:
13052                 return OP_ISHL_IMM;
13053         case OP_ISHR:
13054                 return OP_ISHR_IMM;
13055         case OP_ISHR_UN:
13056                 return OP_ISHR_UN_IMM;
13057
13058         case OP_LADD:
13059                 return OP_LADD_IMM;
13060         case OP_LSUB:
13061                 return OP_LSUB_IMM;
13062         case OP_LAND:
13063                 return OP_LAND_IMM;
13064         case OP_LOR:
13065                 return OP_LOR_IMM;
13066         case OP_LXOR:
13067                 return OP_LXOR_IMM;
13068         case OP_LSHL:
13069                 return OP_LSHL_IMM;
13070         case OP_LSHR:
13071                 return OP_LSHR_IMM;
13072         case OP_LSHR_UN:
13073                 return OP_LSHR_UN_IMM;
13074 #if SIZEOF_REGISTER == 8
13075         case OP_LREM:
13076                 return OP_LREM_IMM;
13077 #endif
13078
13079         case OP_COMPARE:
13080                 return OP_COMPARE_IMM;
13081         case OP_ICOMPARE:
13082                 return OP_ICOMPARE_IMM;
13083         case OP_LCOMPARE:
13084                 return OP_LCOMPARE_IMM;
13085
13086         case OP_STORE_MEMBASE_REG:
13087                 return OP_STORE_MEMBASE_IMM;
13088         case OP_STOREI1_MEMBASE_REG:
13089                 return OP_STOREI1_MEMBASE_IMM;
13090         case OP_STOREI2_MEMBASE_REG:
13091                 return OP_STOREI2_MEMBASE_IMM;
13092         case OP_STOREI4_MEMBASE_REG:
13093                 return OP_STOREI4_MEMBASE_IMM;
13094
13095 #if defined(TARGET_X86) || defined (TARGET_AMD64)
13096         case OP_X86_PUSH:
13097                 return OP_X86_PUSH_IMM;
13098         case OP_X86_COMPARE_MEMBASE_REG:
13099                 return OP_X86_COMPARE_MEMBASE_IMM;
13100 #endif
13101 #if defined(TARGET_AMD64)
13102         case OP_AMD64_ICOMPARE_MEMBASE_REG:
13103                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13104 #endif
13105         case OP_VOIDCALL_REG:
13106                 return OP_VOIDCALL;
13107         case OP_CALL_REG:
13108                 return OP_CALL;
13109         case OP_LCALL_REG:
13110                 return OP_LCALL;
13111         case OP_FCALL_REG:
13112                 return OP_FCALL;
13113         case OP_LOCALLOC:
13114                 return OP_LOCALLOC_IMM;
13115         }
13116
13117         return -1;
13118 }
13119
13120 static int
13121 ldind_to_load_membase (int opcode)
13122 {
13123         switch (opcode) {
13124         case CEE_LDIND_I1:
13125                 return OP_LOADI1_MEMBASE;
13126         case CEE_LDIND_U1:
13127                 return OP_LOADU1_MEMBASE;
13128         case CEE_LDIND_I2:
13129                 return OP_LOADI2_MEMBASE;
13130         case CEE_LDIND_U2:
13131                 return OP_LOADU2_MEMBASE;
13132         case CEE_LDIND_I4:
13133                 return OP_LOADI4_MEMBASE;
13134         case CEE_LDIND_U4:
13135                 return OP_LOADU4_MEMBASE;
13136         case CEE_LDIND_I:
13137                 return OP_LOAD_MEMBASE;
13138         case CEE_LDIND_REF:
13139                 return OP_LOAD_MEMBASE;
13140         case CEE_LDIND_I8:
13141                 return OP_LOADI8_MEMBASE;
13142         case CEE_LDIND_R4:
13143                 return OP_LOADR4_MEMBASE;
13144         case CEE_LDIND_R8:
13145                 return OP_LOADR8_MEMBASE;
13146         default:
13147                 g_assert_not_reached ();
13148         }
13149
13150         return -1;
13151 }
13152
13153 static int
13154 stind_to_store_membase (int opcode)
13155 {
13156         switch (opcode) {
13157         case CEE_STIND_I1:
13158                 return OP_STOREI1_MEMBASE_REG;
13159         case CEE_STIND_I2:
13160                 return OP_STOREI2_MEMBASE_REG;
13161         case CEE_STIND_I4:
13162                 return OP_STOREI4_MEMBASE_REG;
13163         case CEE_STIND_I:
13164         case CEE_STIND_REF:
13165                 return OP_STORE_MEMBASE_REG;
13166         case CEE_STIND_I8:
13167                 return OP_STOREI8_MEMBASE_REG;
13168         case CEE_STIND_R4:
13169                 return OP_STORER4_MEMBASE_REG;
13170         case CEE_STIND_R8:
13171                 return OP_STORER8_MEMBASE_REG;
13172         default:
13173                 g_assert_not_reached ();
13174         }
13175
13176         return -1;
13177 }
13178
13179 int
13180 mono_load_membase_to_load_mem (int opcode)
13181 {
13182         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
13183 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13184         switch (opcode) {
13185         case OP_LOAD_MEMBASE:
13186                 return OP_LOAD_MEM;
13187         case OP_LOADU1_MEMBASE:
13188                 return OP_LOADU1_MEM;
13189         case OP_LOADU2_MEMBASE:
13190                 return OP_LOADU2_MEM;
13191         case OP_LOADI4_MEMBASE:
13192                 return OP_LOADI4_MEM;
13193         case OP_LOADU4_MEMBASE:
13194                 return OP_LOADU4_MEM;
13195 #if SIZEOF_REGISTER == 8
13196         case OP_LOADI8_MEMBASE:
13197                 return OP_LOADI8_MEM;
13198 #endif
13199         }
13200 #endif
13201
13202         return -1;
13203 }
13204
13205 static inline int
13206 op_to_op_dest_membase (int store_opcode, int opcode)
13207 {
13208 #if defined(TARGET_X86)
13209         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
13210                 return -1;
13211
13212         switch (opcode) {
13213         case OP_IADD:
13214                 return OP_X86_ADD_MEMBASE_REG;
13215         case OP_ISUB:
13216                 return OP_X86_SUB_MEMBASE_REG;
13217         case OP_IAND:
13218                 return OP_X86_AND_MEMBASE_REG;
13219         case OP_IOR:
13220                 return OP_X86_OR_MEMBASE_REG;
13221         case OP_IXOR:
13222                 return OP_X86_XOR_MEMBASE_REG;
13223         case OP_ADD_IMM:
13224         case OP_IADD_IMM:
13225                 return OP_X86_ADD_MEMBASE_IMM;
13226         case OP_SUB_IMM:
13227         case OP_ISUB_IMM:
13228                 return OP_X86_SUB_MEMBASE_IMM;
13229         case OP_AND_IMM:
13230         case OP_IAND_IMM:
13231                 return OP_X86_AND_MEMBASE_IMM;
13232         case OP_OR_IMM:
13233         case OP_IOR_IMM:
13234                 return OP_X86_OR_MEMBASE_IMM;
13235         case OP_XOR_IMM:
13236         case OP_IXOR_IMM:
13237                 return OP_X86_XOR_MEMBASE_IMM;
13238         case OP_MOVE:
13239                 return OP_NOP;
13240         }
13241 #endif
13242
13243 #if defined(TARGET_AMD64)
13244         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
13245                 return -1;
13246
13247         switch (opcode) {
13248         case OP_IADD:
13249                 return OP_X86_ADD_MEMBASE_REG;
13250         case OP_ISUB:
13251                 return OP_X86_SUB_MEMBASE_REG;
13252         case OP_IAND:
13253                 return OP_X86_AND_MEMBASE_REG;
13254         case OP_IOR:
13255                 return OP_X86_OR_MEMBASE_REG;
13256         case OP_IXOR:
13257                 return OP_X86_XOR_MEMBASE_REG;
13258         case OP_IADD_IMM:
13259                 return OP_X86_ADD_MEMBASE_IMM;
13260         case OP_ISUB_IMM:
13261                 return OP_X86_SUB_MEMBASE_IMM;
13262         case OP_IAND_IMM:
13263                 return OP_X86_AND_MEMBASE_IMM;
13264         case OP_IOR_IMM:
13265                 return OP_X86_OR_MEMBASE_IMM;
13266         case OP_IXOR_IMM:
13267                 return OP_X86_XOR_MEMBASE_IMM;
13268         case OP_LADD:
13269                 return OP_AMD64_ADD_MEMBASE_REG;
13270         case OP_LSUB:
13271                 return OP_AMD64_SUB_MEMBASE_REG;
13272         case OP_LAND:
13273                 return OP_AMD64_AND_MEMBASE_REG;
13274         case OP_LOR:
13275                 return OP_AMD64_OR_MEMBASE_REG;
13276         case OP_LXOR:
13277                 return OP_AMD64_XOR_MEMBASE_REG;
13278         case OP_ADD_IMM:
13279         case OP_LADD_IMM:
13280                 return OP_AMD64_ADD_MEMBASE_IMM;
13281         case OP_SUB_IMM:
13282         case OP_LSUB_IMM:
13283                 return OP_AMD64_SUB_MEMBASE_IMM;
13284         case OP_AND_IMM:
13285         case OP_LAND_IMM:
13286                 return OP_AMD64_AND_MEMBASE_IMM;
13287         case OP_OR_IMM:
13288         case OP_LOR_IMM:
13289                 return OP_AMD64_OR_MEMBASE_IMM;
13290         case OP_XOR_IMM:
13291         case OP_LXOR_IMM:
13292                 return OP_AMD64_XOR_MEMBASE_IMM;
13293         case OP_MOVE:
13294                 return OP_NOP;
13295         }
13296 #endif
13297
13298         return -1;
13299 }
13300
13301 static inline int
13302 op_to_op_store_membase (int store_opcode, int opcode)
13303 {
13304 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13305         switch (opcode) {
13306         case OP_ICEQ:
13307                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13308                         return OP_X86_SETEQ_MEMBASE;
13309         case OP_CNE:
13310                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13311                         return OP_X86_SETNE_MEMBASE;
13312         }
13313 #endif
13314
13315         return -1;
13316 }
13317
13318 static inline int
13319 op_to_op_src1_membase (MonoCompile *cfg, int load_opcode, int opcode)
13320 {
13321 #ifdef TARGET_X86
13322         /* FIXME: This has sign extension issues */
13323         /*
13324         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13325                 return OP_X86_COMPARE_MEMBASE8_IMM;
13326         */
13327
13328         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13329                 return -1;
13330
13331         switch (opcode) {
13332         case OP_X86_PUSH:
13333                 return OP_X86_PUSH_MEMBASE;
13334         case OP_COMPARE_IMM:
13335         case OP_ICOMPARE_IMM:
13336                 return OP_X86_COMPARE_MEMBASE_IMM;
13337         case OP_COMPARE:
13338         case OP_ICOMPARE:
13339                 return OP_X86_COMPARE_MEMBASE_REG;
13340         }
13341 #endif
13342
13343 #ifdef TARGET_AMD64
13344         /* FIXME: This has sign extension issues */
13345         /*
13346         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13347                 return OP_X86_COMPARE_MEMBASE8_IMM;
13348         */
13349
13350         switch (opcode) {
13351         case OP_X86_PUSH:
13352                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
13353                         return OP_X86_PUSH_MEMBASE;
13354                 break;
13355                 /* FIXME: This only works for 32 bit immediates
13356         case OP_COMPARE_IMM:
13357         case OP_LCOMPARE_IMM:
13358                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13359                         return OP_AMD64_COMPARE_MEMBASE_IMM;
13360                 */
13361         case OP_ICOMPARE_IMM:
13362                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13363                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13364                 break;
13365         case OP_COMPARE:
13366         case OP_LCOMPARE:
13367                 if (cfg->backend->ilp32 && load_opcode == OP_LOAD_MEMBASE)
13368                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13369                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
13370                         return OP_AMD64_COMPARE_MEMBASE_REG;
13371                 break;
13372         case OP_ICOMPARE:
13373                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13374                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13375                 break;
13376         }
13377 #endif
13378
13379         return -1;
13380 }
13381
13382 static inline int
13383 op_to_op_src2_membase (MonoCompile *cfg, int load_opcode, int opcode)
13384 {
13385 #ifdef TARGET_X86
13386         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13387                 return -1;
13388         
13389         switch (opcode) {
13390         case OP_COMPARE:
13391         case OP_ICOMPARE:
13392                 return OP_X86_COMPARE_REG_MEMBASE;
13393         case OP_IADD:
13394                 return OP_X86_ADD_REG_MEMBASE;
13395         case OP_ISUB:
13396                 return OP_X86_SUB_REG_MEMBASE;
13397         case OP_IAND:
13398                 return OP_X86_AND_REG_MEMBASE;
13399         case OP_IOR:
13400                 return OP_X86_OR_REG_MEMBASE;
13401         case OP_IXOR:
13402                 return OP_X86_XOR_REG_MEMBASE;
13403         }
13404 #endif
13405
13406 #ifdef TARGET_AMD64
13407         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && cfg->backend->ilp32)) {
13408                 switch (opcode) {
13409                 case OP_ICOMPARE:
13410                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
13411                 case OP_IADD:
13412                         return OP_X86_ADD_REG_MEMBASE;
13413                 case OP_ISUB:
13414                         return OP_X86_SUB_REG_MEMBASE;
13415                 case OP_IAND:
13416                         return OP_X86_AND_REG_MEMBASE;
13417                 case OP_IOR:
13418                         return OP_X86_OR_REG_MEMBASE;
13419                 case OP_IXOR:
13420                         return OP_X86_XOR_REG_MEMBASE;
13421                 }
13422         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32)) {
13423                 switch (opcode) {
13424                 case OP_COMPARE:
13425                 case OP_LCOMPARE:
13426                         return OP_AMD64_COMPARE_REG_MEMBASE;
13427                 case OP_LADD:
13428                         return OP_AMD64_ADD_REG_MEMBASE;
13429                 case OP_LSUB:
13430                         return OP_AMD64_SUB_REG_MEMBASE;
13431                 case OP_LAND:
13432                         return OP_AMD64_AND_REG_MEMBASE;
13433                 case OP_LOR:
13434                         return OP_AMD64_OR_REG_MEMBASE;
13435                 case OP_LXOR:
13436                         return OP_AMD64_XOR_REG_MEMBASE;
13437                 }
13438         }
13439 #endif
13440
13441         return -1;
13442 }
13443
13444 int
13445 mono_op_to_op_imm_noemul (int opcode)
13446 {
13447         switch (opcode) {
13448 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
13449         case OP_LSHR:
13450         case OP_LSHL:
13451         case OP_LSHR_UN:
13452                 return -1;
13453 #endif
13454 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
13455         case OP_IDIV:
13456         case OP_IDIV_UN:
13457         case OP_IREM:
13458         case OP_IREM_UN:
13459                 return -1;
13460 #endif
13461 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
13462         case OP_IMUL:
13463                 return -1;
13464 #endif
13465         default:
13466                 return mono_op_to_op_imm (opcode);
13467         }
13468 }
13469
13470 /**
13471  * mono_handle_global_vregs:
13472  *
13473  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
13474  * for them.
13475  */
13476 void
13477 mono_handle_global_vregs (MonoCompile *cfg)
13478 {
13479         gint32 *vreg_to_bb;
13480         MonoBasicBlock *bb;
13481         int i, pos;
13482
13483         vreg_to_bb = (gint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
13484
13485 #ifdef MONO_ARCH_SIMD_INTRINSICS
13486         if (cfg->uses_simd_intrinsics)
13487                 mono_simd_simplify_indirection (cfg);
13488 #endif
13489
13490         /* Find local vregs used in more than one bb */
13491         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13492                 MonoInst *ins = bb->code;       
13493                 int block_num = bb->block_num;
13494
13495                 if (cfg->verbose_level > 2)
13496                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
13497
13498                 cfg->cbb = bb;
13499                 for (; ins; ins = ins->next) {
13500                         const char *spec = INS_INFO (ins->opcode);
13501                         int regtype = 0, regindex;
13502                         gint32 prev_bb;
13503
13504                         if (G_UNLIKELY (cfg->verbose_level > 2))
13505                                 mono_print_ins (ins);
13506
13507                         g_assert (ins->opcode >= MONO_CEE_LAST);
13508
13509                         for (regindex = 0; regindex < 4; regindex ++) {
13510                                 int vreg = 0;
13511
13512                                 if (regindex == 0) {
13513                                         regtype = spec [MONO_INST_DEST];
13514                                         if (regtype == ' ')
13515                                                 continue;
13516                                         vreg = ins->dreg;
13517                                 } else if (regindex == 1) {
13518                                         regtype = spec [MONO_INST_SRC1];
13519                                         if (regtype == ' ')
13520                                                 continue;
13521                                         vreg = ins->sreg1;
13522                                 } else if (regindex == 2) {
13523                                         regtype = spec [MONO_INST_SRC2];
13524                                         if (regtype == ' ')
13525                                                 continue;
13526                                         vreg = ins->sreg2;
13527                                 } else if (regindex == 3) {
13528                                         regtype = spec [MONO_INST_SRC3];
13529                                         if (regtype == ' ')
13530                                                 continue;
13531                                         vreg = ins->sreg3;
13532                                 }
13533
13534 #if SIZEOF_REGISTER == 4
13535                                 /* In the LLVM case, the long opcodes are not decomposed */
13536                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
13537                                         /*
13538                                          * Since some instructions reference the original long vreg,
13539                                          * and some reference the two component vregs, it is quite hard
13540                                          * to determine when it needs to be global. So be conservative.
13541                                          */
13542                                         if (!get_vreg_to_inst (cfg, vreg)) {
13543                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13544
13545                                                 if (cfg->verbose_level > 2)
13546                                                         printf ("LONG VREG R%d made global.\n", vreg);
13547                                         }
13548
13549                                         /*
13550                                          * Make the component vregs volatile since the optimizations can
13551                                          * get confused otherwise.
13552                                          */
13553                                         get_vreg_to_inst (cfg, MONO_LVREG_LS (vreg))->flags |= MONO_INST_VOLATILE;
13554                                         get_vreg_to_inst (cfg, MONO_LVREG_MS (vreg))->flags |= MONO_INST_VOLATILE;
13555                                 }
13556 #endif
13557
13558                                 g_assert (vreg != -1);
13559
13560                                 prev_bb = vreg_to_bb [vreg];
13561                                 if (prev_bb == 0) {
13562                                         /* 0 is a valid block num */
13563                                         vreg_to_bb [vreg] = block_num + 1;
13564                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
13565                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
13566                                                 continue;
13567
13568                                         if (!get_vreg_to_inst (cfg, vreg)) {
13569                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13570                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
13571
13572                                                 switch (regtype) {
13573                                                 case 'i':
13574                                                         if (vreg_is_ref (cfg, vreg))
13575                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
13576                                                         else
13577                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
13578                                                         break;
13579                                                 case 'l':
13580                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13581                                                         break;
13582                                                 case 'f':
13583                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
13584                                                         break;
13585                                                 case 'v':
13586                                                 case 'x':
13587                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
13588                                                         break;
13589                                                 default:
13590                                                         g_assert_not_reached ();
13591                                                 }
13592                                         }
13593
13594                                         /* Flag as having been used in more than one bb */
13595                                         vreg_to_bb [vreg] = -1;
13596                                 }
13597                         }
13598                 }
13599         }
13600
13601         /* If a variable is used in only one bblock, convert it into a local vreg */
13602         for (i = 0; i < cfg->num_varinfo; i++) {
13603                 MonoInst *var = cfg->varinfo [i];
13604                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
13605
13606                 switch (var->type) {
13607                 case STACK_I4:
13608                 case STACK_OBJ:
13609                 case STACK_PTR:
13610                 case STACK_MP:
13611                 case STACK_VTYPE:
13612 #if SIZEOF_REGISTER == 8
13613                 case STACK_I8:
13614 #endif
13615 #if !defined(TARGET_X86)
13616                 /* Enabling this screws up the fp stack on x86 */
13617                 case STACK_R8:
13618 #endif
13619                         if (mono_arch_is_soft_float ())
13620                                 break;
13621
13622                         /*
13623                         if (var->type == STACK_VTYPE && cfg->gsharedvt && mini_is_gsharedvt_variable_type (var->inst_vtype))
13624                                 break;
13625                         */
13626
13627                         /* Arguments are implicitly global */
13628                         /* Putting R4 vars into registers doesn't work currently */
13629                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
13630                         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) {
13631                                 /* 
13632                                  * Make that the variable's liveness interval doesn't contain a call, since
13633                                  * that would cause the lvreg to be spilled, making the whole optimization
13634                                  * useless.
13635                                  */
13636                                 /* This is too slow for JIT compilation */
13637 #if 0
13638                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
13639                                         MonoInst *ins;
13640                                         int def_index, call_index, ins_index;
13641                                         gboolean spilled = FALSE;
13642
13643                                         def_index = -1;
13644                                         call_index = -1;
13645                                         ins_index = 0;
13646                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
13647                                                 const char *spec = INS_INFO (ins->opcode);
13648
13649                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
13650                                                         def_index = ins_index;
13651
13652                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
13653                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
13654                                                         if (call_index > def_index) {
13655                                                                 spilled = TRUE;
13656                                                                 break;
13657                                                         }
13658                                                 }
13659
13660                                                 if (MONO_IS_CALL (ins))
13661                                                         call_index = ins_index;
13662
13663                                                 ins_index ++;
13664                                         }
13665
13666                                         if (spilled)
13667                                                 break;
13668                                 }
13669 #endif
13670
13671                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13672                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
13673                                 var->flags |= MONO_INST_IS_DEAD;
13674                                 cfg->vreg_to_inst [var->dreg] = NULL;
13675                         }
13676                         break;
13677                 }
13678         }
13679
13680         /* 
13681          * Compress the varinfo and vars tables so the liveness computation is faster and
13682          * takes up less space.
13683          */
13684         pos = 0;
13685         for (i = 0; i < cfg->num_varinfo; ++i) {
13686                 MonoInst *var = cfg->varinfo [i];
13687                 if (pos < i && cfg->locals_start == i)
13688                         cfg->locals_start = pos;
13689                 if (!(var->flags & MONO_INST_IS_DEAD)) {
13690                         if (pos < i) {
13691                                 cfg->varinfo [pos] = cfg->varinfo [i];
13692                                 cfg->varinfo [pos]->inst_c0 = pos;
13693                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
13694                                 cfg->vars [pos].idx = pos;
13695 #if SIZEOF_REGISTER == 4
13696                                 if (cfg->varinfo [pos]->type == STACK_I8) {
13697                                         /* Modify the two component vars too */
13698                                         MonoInst *var1;
13699
13700                                         var1 = get_vreg_to_inst (cfg, MONO_LVREG_LS (cfg->varinfo [pos]->dreg));
13701                                         var1->inst_c0 = pos;
13702                                         var1 = get_vreg_to_inst (cfg, MONO_LVREG_MS (cfg->varinfo [pos]->dreg));
13703                                         var1->inst_c0 = pos;
13704                                 }
13705 #endif
13706                         }
13707                         pos ++;
13708                 }
13709         }
13710         cfg->num_varinfo = pos;
13711         if (cfg->locals_start > cfg->num_varinfo)
13712                 cfg->locals_start = cfg->num_varinfo;
13713 }
13714
13715 /*
13716  * mono_allocate_gsharedvt_vars:
13717  *
13718  *   Allocate variables with gsharedvt types to entries in the MonoGSharedVtMethodRuntimeInfo.entries array.
13719  * Initialize cfg->gsharedvt_vreg_to_idx with the mapping between vregs and indexes.
13720  */
13721 void
13722 mono_allocate_gsharedvt_vars (MonoCompile *cfg)
13723 {
13724         int i;
13725
13726         cfg->gsharedvt_vreg_to_idx = (int *)mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
13727
13728         for (i = 0; i < cfg->num_varinfo; ++i) {
13729                 MonoInst *ins = cfg->varinfo [i];
13730                 int idx;
13731
13732                 if (mini_is_gsharedvt_variable_type (ins->inst_vtype)) {
13733                         if (i >= cfg->locals_start) {
13734                                 /* Local */
13735                                 idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
13736                                 cfg->gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
13737                                 ins->opcode = OP_GSHAREDVT_LOCAL;
13738                                 ins->inst_imm = idx;
13739                         } else {
13740                                 /* Arg */
13741                                 cfg->gsharedvt_vreg_to_idx [ins->dreg] = -1;
13742                                 ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
13743                         }
13744                 }
13745         }
13746 }
13747
13748 /**
13749  * mono_spill_global_vars:
13750  *
13751  *   Generate spill code for variables which are not allocated to registers, 
13752  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
13753  * code is generated which could be optimized by the local optimization passes.
13754  */
13755 void
13756 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
13757 {
13758         MonoBasicBlock *bb;
13759         char spec2 [16];
13760         int orig_next_vreg;
13761         guint32 *vreg_to_lvreg;
13762         guint32 *lvregs;
13763         guint32 i, lvregs_len;
13764         gboolean dest_has_lvreg = FALSE;
13765         MonoStackType stacktypes [128];
13766         MonoInst **live_range_start, **live_range_end;
13767         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
13768
13769         *need_local_opts = FALSE;
13770
13771         memset (spec2, 0, sizeof (spec2));
13772
13773         /* FIXME: Move this function to mini.c */
13774         stacktypes ['i'] = STACK_PTR;
13775         stacktypes ['l'] = STACK_I8;
13776         stacktypes ['f'] = STACK_R8;
13777 #ifdef MONO_ARCH_SIMD_INTRINSICS
13778         stacktypes ['x'] = STACK_VTYPE;
13779 #endif
13780
13781 #if SIZEOF_REGISTER == 4
13782         /* Create MonoInsts for longs */
13783         for (i = 0; i < cfg->num_varinfo; i++) {
13784                 MonoInst *ins = cfg->varinfo [i];
13785
13786                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
13787                         switch (ins->type) {
13788                         case STACK_R8:
13789                         case STACK_I8: {
13790                                 MonoInst *tree;
13791
13792                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
13793                                         break;
13794
13795                                 g_assert (ins->opcode == OP_REGOFFSET);
13796
13797                                 tree = get_vreg_to_inst (cfg, MONO_LVREG_LS (ins->dreg));
13798                                 g_assert (tree);
13799                                 tree->opcode = OP_REGOFFSET;
13800                                 tree->inst_basereg = ins->inst_basereg;
13801                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
13802
13803                                 tree = get_vreg_to_inst (cfg, MONO_LVREG_MS (ins->dreg));
13804                                 g_assert (tree);
13805                                 tree->opcode = OP_REGOFFSET;
13806                                 tree->inst_basereg = ins->inst_basereg;
13807                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
13808                                 break;
13809                         }
13810                         default:
13811                                 break;
13812                         }
13813                 }
13814         }
13815 #endif
13816
13817         if (cfg->compute_gc_maps) {
13818                 /* registers need liveness info even for !non refs */
13819                 for (i = 0; i < cfg->num_varinfo; i++) {
13820                         MonoInst *ins = cfg->varinfo [i];
13821
13822                         if (ins->opcode == OP_REGVAR)
13823                                 ins->flags |= MONO_INST_GC_TRACK;
13824                 }
13825         }
13826                 
13827         /* FIXME: widening and truncation */
13828
13829         /*
13830          * As an optimization, when a variable allocated to the stack is first loaded into 
13831          * an lvreg, we will remember the lvreg and use it the next time instead of loading
13832          * the variable again.
13833          */
13834         orig_next_vreg = cfg->next_vreg;
13835         vreg_to_lvreg = (guint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
13836         lvregs = (guint32 *)mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
13837         lvregs_len = 0;
13838
13839         /* 
13840          * These arrays contain the first and last instructions accessing a given
13841          * variable.
13842          * Since we emit bblocks in the same order we process them here, and we
13843          * don't split live ranges, these will precisely describe the live range of
13844          * the variable, i.e. the instruction range where a valid value can be found
13845          * in the variables location.
13846          * The live range is computed using the liveness info computed by the liveness pass.
13847          * We can't use vmv->range, since that is an abstract live range, and we need
13848          * one which is instruction precise.
13849          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
13850          */
13851         /* FIXME: Only do this if debugging info is requested */
13852         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
13853         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
13854         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
13855         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
13856         
13857         /* Add spill loads/stores */
13858         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13859                 MonoInst *ins;
13860
13861                 if (cfg->verbose_level > 2)
13862                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
13863
13864                 /* Clear vreg_to_lvreg array */
13865                 for (i = 0; i < lvregs_len; i++)
13866                         vreg_to_lvreg [lvregs [i]] = 0;
13867                 lvregs_len = 0;
13868
13869                 cfg->cbb = bb;
13870                 MONO_BB_FOR_EACH_INS (bb, ins) {
13871                         const char *spec = INS_INFO (ins->opcode);
13872                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
13873                         gboolean store, no_lvreg;
13874                         int sregs [MONO_MAX_SRC_REGS];
13875
13876                         if (G_UNLIKELY (cfg->verbose_level > 2))
13877                                 mono_print_ins (ins);
13878
13879                         if (ins->opcode == OP_NOP)
13880                                 continue;
13881
13882                         /* 
13883                          * We handle LDADDR here as well, since it can only be decomposed
13884                          * when variable addresses are known.
13885                          */
13886                         if (ins->opcode == OP_LDADDR) {
13887                                 MonoInst *var = (MonoInst *)ins->inst_p0;
13888
13889                                 if (var->opcode == OP_VTARG_ADDR) {
13890                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
13891                                         MonoInst *vtaddr = var->inst_left;
13892                                         if (vtaddr->opcode == OP_REGVAR) {
13893                                                 ins->opcode = OP_MOVE;
13894                                                 ins->sreg1 = vtaddr->dreg;
13895                                         }
13896                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
13897                                                 ins->opcode = OP_LOAD_MEMBASE;
13898                                                 ins->inst_basereg = vtaddr->inst_basereg;
13899                                                 ins->inst_offset = vtaddr->inst_offset;
13900                                         } else
13901                                                 NOT_IMPLEMENTED;
13902                                 } else if (cfg->gsharedvt && cfg->gsharedvt_vreg_to_idx [var->dreg] < 0) {
13903                                         /* gsharedvt arg passed by ref */
13904                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
13905
13906                                         ins->opcode = OP_LOAD_MEMBASE;
13907                                         ins->inst_basereg = var->inst_basereg;
13908                                         ins->inst_offset = var->inst_offset;
13909                                 } else if (cfg->gsharedvt && cfg->gsharedvt_vreg_to_idx [var->dreg]) {
13910                                         MonoInst *load, *load2, *load3;
13911                                         int idx = cfg->gsharedvt_vreg_to_idx [var->dreg] - 1;
13912                                         int reg1, reg2, reg3;
13913                                         MonoInst *info_var = cfg->gsharedvt_info_var;
13914                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
13915
13916                                         /*
13917                                          * gsharedvt local.
13918                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
13919                                          */
13920
13921                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
13922
13923                                         g_assert (info_var);
13924                                         g_assert (locals_var);
13925
13926                                         /* Mark the instruction used to compute the locals var as used */
13927                                         cfg->gsharedvt_locals_var_ins = NULL;
13928
13929                                         /* Load the offset */
13930                                         if (info_var->opcode == OP_REGOFFSET) {
13931                                                 reg1 = alloc_ireg (cfg);
13932                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
13933                                         } else if (info_var->opcode == OP_REGVAR) {
13934                                                 load = NULL;
13935                                                 reg1 = info_var->dreg;
13936                                         } else {
13937                                                 g_assert_not_reached ();
13938                                         }
13939                                         reg2 = alloc_ireg (cfg);
13940                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
13941                                         /* Load the locals area address */
13942                                         reg3 = alloc_ireg (cfg);
13943                                         if (locals_var->opcode == OP_REGOFFSET) {
13944                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
13945                                         } else if (locals_var->opcode == OP_REGVAR) {
13946                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
13947                                         } else {
13948                                                 g_assert_not_reached ();
13949                                         }
13950                                         /* Compute the address */
13951                                         ins->opcode = OP_PADD;
13952                                         ins->sreg1 = reg3;
13953                                         ins->sreg2 = reg2;
13954
13955                                         mono_bblock_insert_before_ins (bb, ins, load3);
13956                                         mono_bblock_insert_before_ins (bb, load3, load2);
13957                                         if (load)
13958                                                 mono_bblock_insert_before_ins (bb, load2, load);
13959                                 } else {
13960                                         g_assert (var->opcode == OP_REGOFFSET);
13961
13962                                         ins->opcode = OP_ADD_IMM;
13963                                         ins->sreg1 = var->inst_basereg;
13964                                         ins->inst_imm = var->inst_offset;
13965                                 }
13966
13967                                 *need_local_opts = TRUE;
13968                                 spec = INS_INFO (ins->opcode);
13969                         }
13970
13971                         if (ins->opcode < MONO_CEE_LAST) {
13972                                 mono_print_ins (ins);
13973                                 g_assert_not_reached ();
13974                         }
13975
13976                         /*
13977                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
13978                          * src register.
13979                          * FIXME:
13980                          */
13981                         if (MONO_IS_STORE_MEMBASE (ins)) {
13982                                 tmp_reg = ins->dreg;
13983                                 ins->dreg = ins->sreg2;
13984                                 ins->sreg2 = tmp_reg;
13985                                 store = TRUE;
13986
13987                                 spec2 [MONO_INST_DEST] = ' ';
13988                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
13989                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
13990                                 spec2 [MONO_INST_SRC3] = ' ';
13991                                 spec = spec2;
13992                         } else if (MONO_IS_STORE_MEMINDEX (ins))
13993                                 g_assert_not_reached ();
13994                         else
13995                                 store = FALSE;
13996                         no_lvreg = FALSE;
13997
13998                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
13999                                 printf ("\t %.3s %d", spec, ins->dreg);
14000                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
14001                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
14002                                         printf (" %d", sregs [srcindex]);
14003                                 printf ("\n");
14004                         }
14005
14006                         /***************/
14007                         /*    DREG     */
14008                         /***************/
14009                         regtype = spec [MONO_INST_DEST];
14010                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
14011                         prev_dreg = -1;
14012
14013                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
14014                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
14015                                 MonoInst *store_ins;
14016                                 int store_opcode;
14017                                 MonoInst *def_ins = ins;
14018                                 int dreg = ins->dreg; /* The original vreg */
14019
14020                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
14021
14022                                 if (var->opcode == OP_REGVAR) {
14023                                         ins->dreg = var->dreg;
14024                                 } 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)) {
14025                                         /* 
14026                                          * Instead of emitting a load+store, use a _membase opcode.
14027                                          */
14028                                         g_assert (var->opcode == OP_REGOFFSET);
14029                                         if (ins->opcode == OP_MOVE) {
14030                                                 NULLIFY_INS (ins);
14031                                                 def_ins = NULL;
14032                                         } else {
14033                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
14034                                                 ins->inst_basereg = var->inst_basereg;
14035                                                 ins->inst_offset = var->inst_offset;
14036                                                 ins->dreg = -1;
14037                                         }
14038                                         spec = INS_INFO (ins->opcode);
14039                                 } else {
14040                                         guint32 lvreg;
14041
14042                                         g_assert (var->opcode == OP_REGOFFSET);
14043
14044                                         prev_dreg = ins->dreg;
14045
14046                                         /* Invalidate any previous lvreg for this vreg */
14047                                         vreg_to_lvreg [ins->dreg] = 0;
14048
14049                                         lvreg = 0;
14050
14051                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
14052                                                 regtype = 'l';
14053                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
14054                                         }
14055
14056                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
14057
14058 #if SIZEOF_REGISTER != 8
14059                                         if (regtype == 'l') {
14060                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET, MONO_LVREG_LS (ins->dreg));
14061                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14062                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET, MONO_LVREG_MS (ins->dreg));
14063                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14064                                                 def_ins = store_ins;
14065                                         }
14066                                         else
14067 #endif
14068                                         {
14069                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
14070
14071                                                 /* Try to fuse the store into the instruction itself */
14072                                                 /* FIXME: Add more instructions */
14073                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
14074                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
14075                                                         ins->inst_imm = ins->inst_c0;
14076                                                         ins->inst_destbasereg = var->inst_basereg;
14077                                                         ins->inst_offset = var->inst_offset;
14078                                                         spec = INS_INFO (ins->opcode);
14079                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE) || (ins->opcode == OP_RMOVE))) {
14080                                                         ins->opcode = store_opcode;
14081                                                         ins->inst_destbasereg = var->inst_basereg;
14082                                                         ins->inst_offset = var->inst_offset;
14083
14084                                                         no_lvreg = TRUE;
14085
14086                                                         tmp_reg = ins->dreg;
14087                                                         ins->dreg = ins->sreg2;
14088                                                         ins->sreg2 = tmp_reg;
14089                                                         store = TRUE;
14090
14091                                                         spec2 [MONO_INST_DEST] = ' ';
14092                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14093                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14094                                                         spec2 [MONO_INST_SRC3] = ' ';
14095                                                         spec = spec2;
14096                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
14097                                                         // FIXME: The backends expect the base reg to be in inst_basereg
14098                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
14099                                                         ins->dreg = -1;
14100                                                         ins->inst_basereg = var->inst_basereg;
14101                                                         ins->inst_offset = var->inst_offset;
14102                                                         spec = INS_INFO (ins->opcode);
14103                                                 } else {
14104                                                         /* printf ("INS: "); mono_print_ins (ins); */
14105                                                         /* Create a store instruction */
14106                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
14107
14108                                                         /* Insert it after the instruction */
14109                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
14110
14111                                                         def_ins = store_ins;
14112
14113                                                         /* 
14114                                                          * We can't assign ins->dreg to var->dreg here, since the
14115                                                          * sregs could use it. So set a flag, and do it after
14116                                                          * the sregs.
14117                                                          */
14118                                                         if ((!cfg->backend->use_fpstack || ((store_opcode != OP_STORER8_MEMBASE_REG) && (store_opcode != OP_STORER4_MEMBASE_REG))) && !((var)->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT)))
14119                                                                 dest_has_lvreg = TRUE;
14120                                                 }
14121                                         }
14122                                 }
14123
14124                                 if (def_ins && !live_range_start [dreg]) {
14125                                         live_range_start [dreg] = def_ins;
14126                                         live_range_start_bb [dreg] = bb;
14127                                 }
14128
14129                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
14130                                         MonoInst *tmp;
14131
14132                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
14133                                         tmp->inst_c1 = dreg;
14134                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
14135                                 }
14136                         }
14137
14138                         /************/
14139                         /*  SREGS   */
14140                         /************/
14141                         num_sregs = mono_inst_get_src_registers (ins, sregs);
14142                         for (srcindex = 0; srcindex < 3; ++srcindex) {
14143                                 regtype = spec [MONO_INST_SRC1 + srcindex];
14144                                 sreg = sregs [srcindex];
14145
14146                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
14147                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
14148                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
14149                                         MonoInst *use_ins = ins;
14150                                         MonoInst *load_ins;
14151                                         guint32 load_opcode;
14152
14153                                         if (var->opcode == OP_REGVAR) {
14154                                                 sregs [srcindex] = var->dreg;
14155                                                 //mono_inst_set_src_registers (ins, sregs);
14156                                                 live_range_end [sreg] = use_ins;
14157                                                 live_range_end_bb [sreg] = bb;
14158
14159                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14160                                                         MonoInst *tmp;
14161
14162                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14163                                                         /* var->dreg is a hreg */
14164                                                         tmp->inst_c1 = sreg;
14165                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
14166                                                 }
14167
14168                                                 continue;
14169                                         }
14170
14171                                         g_assert (var->opcode == OP_REGOFFSET);
14172                                                 
14173                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
14174
14175                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
14176
14177                                         if (vreg_to_lvreg [sreg]) {
14178                                                 g_assert (vreg_to_lvreg [sreg] != -1);
14179
14180                                                 /* The variable is already loaded to an lvreg */
14181                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14182                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
14183                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
14184                                                 //mono_inst_set_src_registers (ins, sregs);
14185                                                 continue;
14186                                         }
14187
14188                                         /* Try to fuse the load into the instruction */
14189                                         if ((srcindex == 0) && (op_to_op_src1_membase (cfg, load_opcode, ins->opcode) != -1)) {
14190                                                 ins->opcode = op_to_op_src1_membase (cfg, load_opcode, ins->opcode);
14191                                                 sregs [0] = var->inst_basereg;
14192                                                 //mono_inst_set_src_registers (ins, sregs);
14193                                                 ins->inst_offset = var->inst_offset;
14194                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (cfg, load_opcode, ins->opcode) != -1)) {
14195                                                 ins->opcode = op_to_op_src2_membase (cfg, load_opcode, ins->opcode);
14196                                                 sregs [1] = var->inst_basereg;
14197                                                 //mono_inst_set_src_registers (ins, sregs);
14198                                                 ins->inst_offset = var->inst_offset;
14199                                         } else {
14200                                                 if (MONO_IS_REAL_MOVE (ins)) {
14201                                                         ins->opcode = OP_NOP;
14202                                                         sreg = ins->dreg;
14203                                                 } else {
14204                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
14205
14206                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
14207
14208                                                         if ((!cfg->backend->use_fpstack || ((load_opcode != OP_LOADR8_MEMBASE) && (load_opcode != OP_LOADR4_MEMBASE))) && !((var)->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT)) && !no_lvreg) {
14209                                                                 if (var->dreg == prev_dreg) {
14210                                                                         /*
14211                                                                          * sreg refers to the value loaded by the load
14212                                                                          * emitted below, but we need to use ins->dreg
14213                                                                          * since it refers to the store emitted earlier.
14214                                                                          */
14215                                                                         sreg = ins->dreg;
14216                                                                 }
14217                                                                 g_assert (sreg != -1);
14218                                                                 vreg_to_lvreg [var->dreg] = sreg;
14219                                                                 g_assert (lvregs_len < 1024);
14220                                                                 lvregs [lvregs_len ++] = var->dreg;
14221                                                         }
14222                                                 }
14223
14224                                                 sregs [srcindex] = sreg;
14225                                                 //mono_inst_set_src_registers (ins, sregs);
14226
14227 #if SIZEOF_REGISTER != 8
14228                                                 if (regtype == 'l') {
14229                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_MS (sreg), var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
14230                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14231                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_LS (sreg), var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
14232                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14233                                                         use_ins = load_ins;
14234                                                 }
14235                                                 else
14236 #endif
14237                                                 {
14238 #if SIZEOF_REGISTER == 4
14239                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
14240 #endif
14241                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
14242                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14243                                                         use_ins = load_ins;
14244                                                 }
14245                                         }
14246
14247                                         if (var->dreg < orig_next_vreg) {
14248                                                 live_range_end [var->dreg] = use_ins;
14249                                                 live_range_end_bb [var->dreg] = bb;
14250                                         }
14251
14252                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14253                                                 MonoInst *tmp;
14254
14255                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14256                                                 tmp->inst_c1 = var->dreg;
14257                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
14258                                         }
14259                                 }
14260                         }
14261                         mono_inst_set_src_registers (ins, sregs);
14262
14263                         if (dest_has_lvreg) {
14264                                 g_assert (ins->dreg != -1);
14265                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
14266                                 g_assert (lvregs_len < 1024);
14267                                 lvregs [lvregs_len ++] = prev_dreg;
14268                                 dest_has_lvreg = FALSE;
14269                         }
14270
14271                         if (store) {
14272                                 tmp_reg = ins->dreg;
14273                                 ins->dreg = ins->sreg2;
14274                                 ins->sreg2 = tmp_reg;
14275                         }
14276
14277                         if (MONO_IS_CALL (ins)) {
14278                                 /* Clear vreg_to_lvreg array */
14279                                 for (i = 0; i < lvregs_len; i++)
14280                                         vreg_to_lvreg [lvregs [i]] = 0;
14281                                 lvregs_len = 0;
14282                         } else if (ins->opcode == OP_NOP) {
14283                                 ins->dreg = -1;
14284                                 MONO_INST_NULLIFY_SREGS (ins);
14285                         }
14286
14287                         if (cfg->verbose_level > 2)
14288                                 mono_print_ins_index (1, ins);
14289                 }
14290
14291                 /* Extend the live range based on the liveness info */
14292                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
14293                         for (i = 0; i < cfg->num_varinfo; i ++) {
14294                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
14295
14296                                 if (vreg_is_volatile (cfg, vi->vreg))
14297                                         /* The liveness info is incomplete */
14298                                         continue;
14299
14300                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
14301                                         /* Live from at least the first ins of this bb */
14302                                         live_range_start [vi->vreg] = bb->code;
14303                                         live_range_start_bb [vi->vreg] = bb;
14304                                 }
14305
14306                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
14307                                         /* Live at least until the last ins of this bb */
14308                                         live_range_end [vi->vreg] = bb->last_ins;
14309                                         live_range_end_bb [vi->vreg] = bb;
14310                                 }
14311                         }
14312                 }
14313         }
14314         
14315         /*
14316          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
14317          * by storing the current native offset into MonoMethodVar->live_range_start/end.
14318          */
14319         if (cfg->backend->have_liverange_ops && cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
14320                 for (i = 0; i < cfg->num_varinfo; ++i) {
14321                         int vreg = MONO_VARINFO (cfg, i)->vreg;
14322                         MonoInst *ins;
14323
14324                         if (live_range_start [vreg]) {
14325                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
14326                                 ins->inst_c0 = i;
14327                                 ins->inst_c1 = vreg;
14328                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
14329                         }
14330                         if (live_range_end [vreg]) {
14331                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
14332                                 ins->inst_c0 = i;
14333                                 ins->inst_c1 = vreg;
14334                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
14335                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
14336                                 else
14337                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
14338                         }
14339                 }
14340         }
14341
14342         if (cfg->gsharedvt_locals_var_ins) {
14343                 /* Nullify if unused */
14344                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
14345                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
14346         }
14347
14348         g_free (live_range_start);
14349         g_free (live_range_end);
14350         g_free (live_range_start_bb);
14351         g_free (live_range_end_bb);
14352 }
14353
14354
14355 /**
14356  * FIXME:
14357  * - use 'iadd' instead of 'int_add'
14358  * - handling ovf opcodes: decompose in method_to_ir.
14359  * - unify iregs/fregs
14360  *   -> partly done, the missing parts are:
14361  *   - a more complete unification would involve unifying the hregs as well, so
14362  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
14363  *     would no longer map to the machine hregs, so the code generators would need to
14364  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
14365  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
14366  *     fp/non-fp branches speeds it up by about 15%.
14367  * - use sext/zext opcodes instead of shifts
14368  * - add OP_ICALL
14369  * - get rid of TEMPLOADs if possible and use vregs instead
14370  * - clean up usage of OP_P/OP_ opcodes
14371  * - cleanup usage of DUMMY_USE
14372  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
14373  *   stack
14374  * - set the stack type and allocate a dreg in the EMIT_NEW macros
14375  * - get rid of all the <foo>2 stuff when the new JIT is ready.
14376  * - make sure handle_stack_args () is called before the branch is emitted
14377  * - when the new IR is done, get rid of all unused stuff
14378  * - COMPARE/BEQ as separate instructions or unify them ?
14379  *   - keeping them separate allows specialized compare instructions like
14380  *     compare_imm, compare_membase
14381  *   - most back ends unify fp compare+branch, fp compare+ceq
14382  * - integrate mono_save_args into inline_method
14383  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
14384  * - handle long shift opts on 32 bit platforms somehow: they require 
14385  *   3 sregs (2 for arg1 and 1 for arg2)
14386  * - make byref a 'normal' type.
14387  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
14388  *   variable if needed.
14389  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
14390  *   like inline_method.
14391  * - remove inlining restrictions
14392  * - fix LNEG and enable cfold of INEG
14393  * - generalize x86 optimizations like ldelema as a peephole optimization
14394  * - add store_mem_imm for amd64
14395  * - optimize the loading of the interruption flag in the managed->native wrappers
14396  * - avoid special handling of OP_NOP in passes
14397  * - move code inserting instructions into one function/macro.
14398  * - try a coalescing phase after liveness analysis
14399  * - add float -> vreg conversion + local optimizations on !x86
14400  * - figure out how to handle decomposed branches during optimizations, ie.
14401  *   compare+branch, op_jump_table+op_br etc.
14402  * - promote RuntimeXHandles to vregs
14403  * - vtype cleanups:
14404  *   - add a NEW_VARLOADA_VREG macro
14405  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
14406  *   accessing vtype fields.
14407  * - get rid of I8CONST on 64 bit platforms
14408  * - dealing with the increase in code size due to branches created during opcode
14409  *   decomposition:
14410  *   - use extended basic blocks
14411  *     - all parts of the JIT
14412  *     - handle_global_vregs () && local regalloc
14413  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
14414  * - sources of increase in code size:
14415  *   - vtypes
14416  *   - long compares
14417  *   - isinst and castclass
14418  *   - lvregs not allocated to global registers even if used multiple times
14419  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
14420  *   meaningful.
14421  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
14422  * - add all micro optimizations from the old JIT
14423  * - put tree optimizations into the deadce pass
14424  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
14425  *   specific function.
14426  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
14427  *   fcompare + branchCC.
14428  * - create a helper function for allocating a stack slot, taking into account 
14429  *   MONO_CFG_HAS_SPILLUP.
14430  * - merge r68207.
14431  * - merge the ia64 switch changes.
14432  * - optimize mono_regstate2_alloc_int/float.
14433  * - fix the pessimistic handling of variables accessed in exception handler blocks.
14434  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
14435  *   parts of the tree could be separated by other instructions, killing the tree
14436  *   arguments, or stores killing loads etc. Also, should we fold loads into other
14437  *   instructions if the result of the load is used multiple times ?
14438  * - make the REM_IMM optimization in mini-x86.c arch-independent.
14439  * - LAST MERGE: 108395.
14440  * - when returning vtypes in registers, generate IR and append it to the end of the
14441  *   last bb instead of doing it in the epilog.
14442  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
14443  */
14444
14445 /*
14446
14447 NOTES
14448 -----
14449
14450 - When to decompose opcodes:
14451   - earlier: this makes some optimizations hard to implement, since the low level IR
14452   no longer contains the neccessary information. But it is easier to do.
14453   - later: harder to implement, enables more optimizations.
14454 - Branches inside bblocks:
14455   - created when decomposing complex opcodes. 
14456     - branches to another bblock: harmless, but not tracked by the branch 
14457       optimizations, so need to branch to a label at the start of the bblock.
14458     - branches to inside the same bblock: very problematic, trips up the local
14459       reg allocator. Can be fixed by spitting the current bblock, but that is a
14460       complex operation, since some local vregs can become global vregs etc.
14461 - Local/global vregs:
14462   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
14463     local register allocator.
14464   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
14465     structure, created by mono_create_var (). Assigned to hregs or the stack by
14466     the global register allocator.
14467 - When to do optimizations like alu->alu_imm:
14468   - earlier -> saves work later on since the IR will be smaller/simpler
14469   - later -> can work on more instructions
14470 - Handling of valuetypes:
14471   - When a vtype is pushed on the stack, a new temporary is created, an 
14472     instruction computing its address (LDADDR) is emitted and pushed on
14473     the stack. Need to optimize cases when the vtype is used immediately as in
14474     argument passing, stloc etc.
14475 - Instead of the to_end stuff in the old JIT, simply call the function handling
14476   the values on the stack before emitting the last instruction of the bb.
14477 */
14478
14479 #else /* !DISABLE_JIT */
14480
14481 MONO_EMPTY_SOURCE_FILE (method_to_ir);
14482
14483 #endif /* !DISABLE_JIT */