Merge pull request #4023 from lateralusX/jlorenss/test-driver-reporter
[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 static MonoMethodSignature *helper_sig_jit_thread_attach;
160
161 /* type loading helpers */
162 static GENERATE_GET_CLASS_WITH_CACHE (runtime_helpers, System.Runtime.CompilerServices, RuntimeHelpers)
163 static GENERATE_TRY_GET_CLASS_WITH_CACHE (debuggable_attribute, System.Diagnostics, DebuggableAttribute)
164
165 /*
166  * Instruction metadata
167  */
168 #ifdef MINI_OP
169 #undef MINI_OP
170 #endif
171 #ifdef MINI_OP3
172 #undef MINI_OP3
173 #endif
174 #define MINI_OP(a,b,dest,src1,src2) dest, src1, src2, ' ',
175 #define MINI_OP3(a,b,dest,src1,src2,src3) dest, src1, src2, src3,
176 #define NONE ' '
177 #define IREG 'i'
178 #define FREG 'f'
179 #define VREG 'v'
180 #define XREG 'x'
181 #if SIZEOF_REGISTER == 8 && SIZEOF_REGISTER == SIZEOF_VOID_P
182 #define LREG IREG
183 #else
184 #define LREG 'l'
185 #endif
186 /* keep in sync with the enum in mini.h */
187 const char
188 ins_info[] = {
189 #include "mini-ops.h"
190 };
191 #undef MINI_OP
192 #undef MINI_OP3
193
194 #define MINI_OP(a,b,dest,src1,src2) ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0)),
195 #define MINI_OP3(a,b,dest,src1,src2,src3) ((src3) != NONE ? 3 : ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0))),
196 /* 
197  * This should contain the index of the last sreg + 1. This is not the same
198  * as the number of sregs for opcodes like IA64_CMP_EQ_IMM.
199  */
200 const gint8 ins_sreg_counts[] = {
201 #include "mini-ops.h"
202 };
203 #undef MINI_OP
204 #undef MINI_OP3
205
206 #define MONO_INIT_VARINFO(vi,id) do { \
207         (vi)->range.first_use.pos.bid = 0xffff; \
208         (vi)->reg = -1; \
209         (vi)->idx = (id); \
210 } while (0)
211
212 guint32
213 mono_alloc_ireg (MonoCompile *cfg)
214 {
215         return alloc_ireg (cfg);
216 }
217
218 guint32
219 mono_alloc_lreg (MonoCompile *cfg)
220 {
221         return alloc_lreg (cfg);
222 }
223
224 guint32
225 mono_alloc_freg (MonoCompile *cfg)
226 {
227         return alloc_freg (cfg);
228 }
229
230 guint32
231 mono_alloc_preg (MonoCompile *cfg)
232 {
233         return alloc_preg (cfg);
234 }
235
236 guint32
237 mono_alloc_dreg (MonoCompile *cfg, MonoStackType stack_type)
238 {
239         return alloc_dreg (cfg, stack_type);
240 }
241
242 /*
243  * mono_alloc_ireg_ref:
244  *
245  *   Allocate an IREG, and mark it as holding a GC ref.
246  */
247 guint32
248 mono_alloc_ireg_ref (MonoCompile *cfg)
249 {
250         return alloc_ireg_ref (cfg);
251 }
252
253 /*
254  * mono_alloc_ireg_mp:
255  *
256  *   Allocate an IREG, and mark it as holding a managed pointer.
257  */
258 guint32
259 mono_alloc_ireg_mp (MonoCompile *cfg)
260 {
261         return alloc_ireg_mp (cfg);
262 }
263
264 /*
265  * mono_alloc_ireg_copy:
266  *
267  *   Allocate an IREG with the same GC type as VREG.
268  */
269 guint32
270 mono_alloc_ireg_copy (MonoCompile *cfg, guint32 vreg)
271 {
272         if (vreg_is_ref (cfg, vreg))
273                 return alloc_ireg_ref (cfg);
274         else if (vreg_is_mp (cfg, vreg))
275                 return alloc_ireg_mp (cfg);
276         else
277                 return alloc_ireg (cfg);
278 }
279
280 guint
281 mono_type_to_regmove (MonoCompile *cfg, MonoType *type)
282 {
283         if (type->byref)
284                 return OP_MOVE;
285
286         type = mini_get_underlying_type (type);
287 handle_enum:
288         switch (type->type) {
289         case MONO_TYPE_I1:
290         case MONO_TYPE_U1:
291                 return OP_MOVE;
292         case MONO_TYPE_I2:
293         case MONO_TYPE_U2:
294                 return OP_MOVE;
295         case MONO_TYPE_I4:
296         case MONO_TYPE_U4:
297                 return OP_MOVE;
298         case MONO_TYPE_I:
299         case MONO_TYPE_U:
300         case MONO_TYPE_PTR:
301         case MONO_TYPE_FNPTR:
302                 return OP_MOVE;
303         case MONO_TYPE_CLASS:
304         case MONO_TYPE_STRING:
305         case MONO_TYPE_OBJECT:
306         case MONO_TYPE_SZARRAY:
307         case MONO_TYPE_ARRAY:    
308                 return OP_MOVE;
309         case MONO_TYPE_I8:
310         case MONO_TYPE_U8:
311 #if SIZEOF_REGISTER == 8
312                 return OP_MOVE;
313 #else
314                 return OP_LMOVE;
315 #endif
316         case MONO_TYPE_R4:
317                 return cfg->r4fp ? OP_RMOVE : OP_FMOVE;
318         case MONO_TYPE_R8:
319                 return OP_FMOVE;
320         case MONO_TYPE_VALUETYPE:
321                 if (type->data.klass->enumtype) {
322                         type = mono_class_enum_basetype (type->data.klass);
323                         goto handle_enum;
324                 }
325                 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
326                         return OP_XMOVE;
327                 return OP_VMOVE;
328         case MONO_TYPE_TYPEDBYREF:
329                 return OP_VMOVE;
330         case MONO_TYPE_GENERICINST:
331                 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
332                         return OP_XMOVE;
333                 type = &type->data.generic_class->container_class->byval_arg;
334                 goto handle_enum;
335         case MONO_TYPE_VAR:
336         case MONO_TYPE_MVAR:
337                 g_assert (cfg->gshared);
338                 if (mini_type_var_is_vt (type))
339                         return OP_VMOVE;
340                 else
341                         return mono_type_to_regmove (cfg, mini_get_underlying_type (type));
342         default:
343                 g_error ("unknown type 0x%02x in type_to_regstore", type->type);
344         }
345         return -1;
346 }
347
348 void
349 mono_print_bb (MonoBasicBlock *bb, const char *msg)
350 {
351         int i;
352         MonoInst *tree;
353
354         printf ("\n%s %d: [IN: ", msg, bb->block_num);
355         for (i = 0; i < bb->in_count; ++i)
356                 printf (" BB%d(%d)", bb->in_bb [i]->block_num, bb->in_bb [i]->dfn);
357         printf (", OUT: ");
358         for (i = 0; i < bb->out_count; ++i)
359                 printf (" BB%d(%d)", bb->out_bb [i]->block_num, bb->out_bb [i]->dfn);
360         printf (" ]\n");
361         for (tree = bb->code; tree; tree = tree->next)
362                 mono_print_ins_index (-1, tree);
363 }
364
365 void
366 mono_create_helper_signatures (void)
367 {
368         helper_sig_domain_get = mono_create_icall_signature ("ptr");
369         helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
370         helper_sig_llvmonly_imt_trampoline = mono_create_icall_signature ("ptr ptr ptr");
371         helper_sig_jit_thread_attach = mono_create_icall_signature ("ptr ptr");
372 }
373
374 static MONO_NEVER_INLINE void
375 break_on_unverified (void)
376 {
377         if (mini_get_debug_options ()->break_on_unverified)
378                 G_BREAKPOINT ();
379 }
380
381 static MONO_NEVER_INLINE void
382 field_access_failure (MonoCompile *cfg, MonoMethod *method, MonoClassField *field)
383 {
384         char *method_fname = mono_method_full_name (method, TRUE);
385         char *field_fname = mono_field_full_name (field);
386         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
387         mono_error_set_generic_error (&cfg->error, "System", "FieldAccessException", "Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname);
388         g_free (method_fname);
389         g_free (field_fname);
390 }
391
392 static MONO_NEVER_INLINE void
393 inline_failure (MonoCompile *cfg, const char *msg)
394 {
395         if (cfg->verbose_level >= 2)
396                 printf ("inline failed: %s\n", msg);
397         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INLINE_FAILED);
398 }
399
400 static MONO_NEVER_INLINE void
401 gshared_failure (MonoCompile *cfg, int opcode, const char *file, int line)
402 {
403         if (cfg->verbose_level > 2)                                                                                     \
404                 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);
405         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
406 }
407
408 static MONO_NEVER_INLINE void
409 gsharedvt_failure (MonoCompile *cfg, int opcode, const char *file, int line)
410 {
411         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);
412         if (cfg->verbose_level >= 2)
413                 printf ("%s\n", cfg->exception_message);
414         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
415 }
416
417 /*
418  * When using gsharedvt, some instatiations might be verifiable, and some might be not. i.e. 
419  * foo<T> (int i) { ldarg.0; box T; }
420  */
421 #define UNVERIFIED do { \
422         if (cfg->gsharedvt) { \
423                 if (cfg->verbose_level > 2)                                                                     \
424                         printf ("gsharedvt method failed to verify, falling back to instantiation.\n"); \
425                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \
426                 goto exception_exit;                                                                                    \
427         }                                                                                                                                       \
428         break_on_unverified ();                                                                                         \
429         goto unverified;                                                                                                        \
430 } while (0)
431
432 #define GET_BBLOCK(cfg,tblock,ip) do {  \
433                 (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
434                 if (!(tblock)) {        \
435                         if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
436             NEW_BBLOCK (cfg, (tblock)); \
437                         (tblock)->cil_code = (ip);      \
438                         ADD_BBLOCK (cfg, (tblock));     \
439                 } \
440         } while (0)
441
442 #if defined(TARGET_X86) || defined(TARGET_AMD64)
443 #define EMIT_NEW_X86_LEA(cfg,dest,sr1,sr2,shift,imm) do { \
444                 MONO_INST_NEW (cfg, dest, OP_X86_LEA); \
445                 (dest)->dreg = alloc_ireg_mp ((cfg)); \
446                 (dest)->sreg1 = (sr1); \
447                 (dest)->sreg2 = (sr2); \
448                 (dest)->inst_imm = (imm); \
449                 (dest)->backend.shift_amount = (shift); \
450                 MONO_ADD_INS ((cfg)->cbb, (dest)); \
451         } while (0)
452 #endif
453
454 /* Emit conversions so both operands of a binary opcode are of the same type */
455 static void
456 add_widen_op (MonoCompile *cfg, MonoInst *ins, MonoInst **arg1_ref, MonoInst **arg2_ref)
457 {
458         MonoInst *arg1 = *arg1_ref;
459         MonoInst *arg2 = *arg2_ref;
460
461         if (cfg->r4fp &&
462                 ((arg1->type == STACK_R4 && arg2->type == STACK_R8) ||
463                  (arg1->type == STACK_R8 && arg2->type == STACK_R4))) {
464                 MonoInst *conv;
465
466                 /* Mixing r4/r8 is allowed by the spec */
467                 if (arg1->type == STACK_R4) {
468                         int dreg = alloc_freg (cfg);
469
470                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg1->dreg);
471                         conv->type = STACK_R8;
472                         ins->sreg1 = dreg;
473                         *arg1_ref = conv;
474                 }
475                 if (arg2->type == STACK_R4) {
476                         int dreg = alloc_freg (cfg);
477
478                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg2->dreg);
479                         conv->type = STACK_R8;
480                         ins->sreg2 = dreg;
481                         *arg2_ref = conv;
482                 }
483         }
484
485 #if SIZEOF_REGISTER == 8
486         /* FIXME: Need to add many more cases */
487         if ((arg1)->type == STACK_PTR && (arg2)->type == STACK_I4) {
488                 MonoInst *widen;
489
490                 int dr = alloc_preg (cfg);
491                 EMIT_NEW_UNALU (cfg, widen, OP_SEXT_I4, dr, (arg2)->dreg);
492                 (ins)->sreg2 = widen->dreg;
493         }
494 #endif
495 }
496
497 #define ADD_BINOP(op) do {      \
498                 MONO_INST_NEW (cfg, ins, (op)); \
499                 sp -= 2;        \
500                 ins->sreg1 = sp [0]->dreg;      \
501                 ins->sreg2 = sp [1]->dreg;      \
502                 type_from_op (cfg, ins, sp [0], sp [1]);        \
503                 CHECK_TYPE (ins);       \
504                 /* Have to insert a widening op */               \
505         add_widen_op (cfg, ins, &sp [0], &sp [1]);               \
506         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type); \
507         MONO_ADD_INS ((cfg)->cbb, (ins)); \
508         *sp++ = mono_decompose_opcode ((cfg), (ins));   \
509         } while (0)
510
511 #define ADD_UNOP(op) do {       \
512                 MONO_INST_NEW (cfg, ins, (op)); \
513                 sp--;   \
514                 ins->sreg1 = sp [0]->dreg;      \
515                 type_from_op (cfg, ins, sp [0], NULL);  \
516                 CHECK_TYPE (ins);       \
517         (ins)->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type); \
518         MONO_ADD_INS ((cfg)->cbb, (ins)); \
519                 *sp++ = mono_decompose_opcode (cfg, ins);       \
520         } while (0)
521
522 #define ADD_BINCOND(next_block) do {    \
523                 MonoInst *cmp;  \
524                 sp -= 2; \
525                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
526                 cmp->sreg1 = sp [0]->dreg;      \
527                 cmp->sreg2 = sp [1]->dreg;      \
528                 type_from_op (cfg, cmp, sp [0], sp [1]);        \
529                 CHECK_TYPE (cmp);       \
530                 add_widen_op (cfg, cmp, &sp [0], &sp [1]);                                              \
531                 type_from_op (cfg, ins, sp [0], sp [1]);                                                        \
532                 ins->inst_many_bb = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);   \
533                 GET_BBLOCK (cfg, tblock, target);               \
534                 link_bblock (cfg, cfg->cbb, tblock);    \
535                 ins->inst_true_bb = tblock;     \
536                 if ((next_block)) {     \
537                         link_bblock (cfg, cfg->cbb, (next_block));      \
538                         ins->inst_false_bb = (next_block);      \
539                         start_new_bblock = 1;   \
540                 } else {        \
541                         GET_BBLOCK (cfg, tblock, ip);           \
542                         link_bblock (cfg, cfg->cbb, tblock);    \
543                         ins->inst_false_bb = tblock;    \
544                         start_new_bblock = 2;   \
545                 }       \
546                 if (sp != stack_start) {                                                                        \
547                     handle_stack_args (cfg, stack_start, sp - stack_start); \
548                         CHECK_UNVERIFIABLE (cfg); \
549                 } \
550         MONO_ADD_INS (cfg->cbb, cmp); \
551                 MONO_ADD_INS (cfg->cbb, ins);   \
552         } while (0)
553
554 /* *
555  * link_bblock: Links two basic blocks
556  *
557  * links two basic blocks in the control flow graph, the 'from'
558  * argument is the starting block and the 'to' argument is the block
559  * the control flow ends to after 'from'.
560  */
561 static void
562 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
563 {
564         MonoBasicBlock **newa;
565         int i, found;
566
567 #if 0
568         if (from->cil_code) {
569                 if (to->cil_code)
570                         printf ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
571                 else
572                         printf ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
573         } else {
574                 if (to->cil_code)
575                         printf ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
576                 else
577                         printf ("edge from entry to exit\n");
578         }
579 #endif
580
581         found = FALSE;
582         for (i = 0; i < from->out_count; ++i) {
583                 if (to == from->out_bb [i]) {
584                         found = TRUE;
585                         break;
586                 }
587         }
588         if (!found) {
589                 newa = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
590                 for (i = 0; i < from->out_count; ++i) {
591                         newa [i] = from->out_bb [i];
592                 }
593                 newa [i] = to;
594                 from->out_count++;
595                 from->out_bb = newa;
596         }
597
598         found = FALSE;
599         for (i = 0; i < to->in_count; ++i) {
600                 if (from == to->in_bb [i]) {
601                         found = TRUE;
602                         break;
603                 }
604         }
605         if (!found) {
606                 newa = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
607                 for (i = 0; i < to->in_count; ++i) {
608                         newa [i] = to->in_bb [i];
609                 }
610                 newa [i] = from;
611                 to->in_count++;
612                 to->in_bb = newa;
613         }
614 }
615
616 void
617 mono_link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
618 {
619         link_bblock (cfg, from, to);
620 }
621
622 /**
623  * mono_find_block_region:
624  *
625  *   We mark each basic block with a region ID. We use that to avoid BB
626  *   optimizations when blocks are in different regions.
627  *
628  * Returns:
629  *   A region token that encodes where this region is, and information
630  *   about the clause owner for this block.
631  *
632  *   The region encodes the try/catch/filter clause that owns this block
633  *   as well as the type.  -1 is a special value that represents a block
634  *   that is in none of try/catch/filter.
635  */
636 static int
637 mono_find_block_region (MonoCompile *cfg, int offset)
638 {
639         MonoMethodHeader *header = cfg->header;
640         MonoExceptionClause *clause;
641         int i;
642
643         for (i = 0; i < header->num_clauses; ++i) {
644                 clause = &header->clauses [i];
645                 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
646                     (offset < (clause->handler_offset)))
647                         return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
648                            
649                 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
650                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
651                                 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
652                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
653                                 return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
654                         else
655                                 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
656                 }
657         }
658         for (i = 0; i < header->num_clauses; ++i) {
659                 clause = &header->clauses [i];
660
661                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
662                         return ((i + 1) << 8) | clause->flags;
663         }
664
665         return -1;
666 }
667
668 static gboolean
669 ip_in_finally_clause (MonoCompile *cfg, int offset)
670 {
671         MonoMethodHeader *header = cfg->header;
672         MonoExceptionClause *clause;
673         int i;
674
675         for (i = 0; i < header->num_clauses; ++i) {
676                 clause = &header->clauses [i];
677                 if (clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FAULT)
678                         continue;
679
680                 if (MONO_OFFSET_IN_HANDLER (clause, offset))
681                         return TRUE;
682         }
683         return FALSE;
684 }
685
686 static GList*
687 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
688 {
689         MonoMethodHeader *header = cfg->header;
690         MonoExceptionClause *clause;
691         int i;
692         GList *res = NULL;
693
694         for (i = 0; i < header->num_clauses; ++i) {
695                 clause = &header->clauses [i];
696                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
697                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
698                         if (clause->flags == type)
699                                 res = g_list_append (res, clause);
700                 }
701         }
702         return res;
703 }
704
705 static void
706 mono_create_spvar_for_region (MonoCompile *cfg, int region)
707 {
708         MonoInst *var;
709
710         var = (MonoInst *)g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
711         if (var)
712                 return;
713
714         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
715         /* prevent it from being register allocated */
716         var->flags |= MONO_INST_VOLATILE;
717
718         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
719 }
720
721 MonoInst *
722 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
723 {
724         return (MonoInst *)g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
725 }
726
727 static MonoInst*
728 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
729 {
730         MonoInst *var;
731
732         var = (MonoInst *)g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
733         if (var)
734                 return var;
735
736         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
737         /* prevent it from being register allocated */
738         var->flags |= MONO_INST_VOLATILE;
739
740         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
741
742         return var;
743 }
744
745 /*
746  * Returns the type used in the eval stack when @type is loaded.
747  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
748  */
749 void
750 type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
751 {
752         MonoClass *klass;
753
754         type = mini_get_underlying_type (type);
755         inst->klass = klass = mono_class_from_mono_type (type);
756         if (type->byref) {
757                 inst->type = STACK_MP;
758                 return;
759         }
760
761 handle_enum:
762         switch (type->type) {
763         case MONO_TYPE_VOID:
764                 inst->type = STACK_INV;
765                 return;
766         case MONO_TYPE_I1:
767         case MONO_TYPE_U1:
768         case MONO_TYPE_I2:
769         case MONO_TYPE_U2:
770         case MONO_TYPE_I4:
771         case MONO_TYPE_U4:
772                 inst->type = STACK_I4;
773                 return;
774         case MONO_TYPE_I:
775         case MONO_TYPE_U:
776         case MONO_TYPE_PTR:
777         case MONO_TYPE_FNPTR:
778                 inst->type = STACK_PTR;
779                 return;
780         case MONO_TYPE_CLASS:
781         case MONO_TYPE_STRING:
782         case MONO_TYPE_OBJECT:
783         case MONO_TYPE_SZARRAY:
784         case MONO_TYPE_ARRAY:    
785                 inst->type = STACK_OBJ;
786                 return;
787         case MONO_TYPE_I8:
788         case MONO_TYPE_U8:
789                 inst->type = STACK_I8;
790                 return;
791         case MONO_TYPE_R4:
792                 inst->type = cfg->r4_stack_type;
793                 break;
794         case MONO_TYPE_R8:
795                 inst->type = STACK_R8;
796                 return;
797         case MONO_TYPE_VALUETYPE:
798                 if (type->data.klass->enumtype) {
799                         type = mono_class_enum_basetype (type->data.klass);
800                         goto handle_enum;
801                 } else {
802                         inst->klass = klass;
803                         inst->type = STACK_VTYPE;
804                         return;
805                 }
806         case MONO_TYPE_TYPEDBYREF:
807                 inst->klass = mono_defaults.typed_reference_class;
808                 inst->type = STACK_VTYPE;
809                 return;
810         case MONO_TYPE_GENERICINST:
811                 type = &type->data.generic_class->container_class->byval_arg;
812                 goto handle_enum;
813         case MONO_TYPE_VAR:
814         case MONO_TYPE_MVAR:
815                 g_assert (cfg->gshared);
816                 if (mini_is_gsharedvt_type (type)) {
817                         g_assert (cfg->gsharedvt);
818                         inst->type = STACK_VTYPE;
819                 } else {
820                         type_to_eval_stack_type (cfg, mini_get_underlying_type (type), inst);
821                 }
822                 return;
823         default:
824                 g_error ("unknown type 0x%02x in eval stack type", type->type);
825         }
826 }
827
828 /*
829  * The following tables are used to quickly validate the IL code in type_from_op ().
830  */
831 static const char
832 bin_num_table [STACK_MAX] [STACK_MAX] = {
833         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
834         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
835         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
836         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
837         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV, STACK_R8},
838         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
839         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
840         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
841         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4}
842 };
843
844 static const char 
845 neg_table [] = {
846         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4
847 };
848
849 /* reduce the size of this table */
850 static const char
851 bin_int_table [STACK_MAX] [STACK_MAX] = {
852         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
853         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
854         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
855         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, 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         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
859         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
860 };
861
862 static const char
863 bin_comp_table [STACK_MAX] [STACK_MAX] = {
864 /*      Inv i  L  p  F  &  O  vt r4 */
865         {0},
866         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
867         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
868         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
869         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* F, R8 */
870         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
871         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
872         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
873         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* r, r4 */
874 };
875
876 /* reduce the size of this table */
877 static const char
878 shift_table [STACK_MAX] [STACK_MAX] = {
879         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
880         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
881         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
882         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, 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         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
886         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
887 };
888
889 /*
890  * Tables to map from the non-specific opcode to the matching
891  * type-specific opcode.
892  */
893 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
894 static const guint16
895 binops_op_map [STACK_MAX] = {
896         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
897 };
898
899 /* handles from CEE_NEG to CEE_CONV_U8 */
900 static const guint16
901 unops_op_map [STACK_MAX] = {
902         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
903 };
904
905 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
906 static const guint16
907 ovfops_op_map [STACK_MAX] = {
908         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
909 };
910
911 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
912 static const guint16
913 ovf2ops_op_map [STACK_MAX] = {
914         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
915 };
916
917 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
918 static const guint16
919 ovf3ops_op_map [STACK_MAX] = {
920         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
921 };
922
923 /* handles from CEE_BEQ to CEE_BLT_UN */
924 static const guint16
925 beqops_op_map [STACK_MAX] = {
926         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
927 };
928
929 /* handles from CEE_CEQ to CEE_CLT_UN */
930 static const guint16
931 ceqops_op_map [STACK_MAX] = {
932         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
933 };
934
935 /*
936  * Sets ins->type (the type on the eval stack) according to the
937  * type of the opcode and the arguments to it.
938  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
939  *
940  * FIXME: this function sets ins->type unconditionally in some cases, but
941  * it should set it to invalid for some types (a conv.x on an object)
942  */
943 static void
944 type_from_op (MonoCompile *cfg, MonoInst *ins, MonoInst *src1, MonoInst *src2)
945 {
946         switch (ins->opcode) {
947         /* binops */
948         case CEE_ADD:
949         case CEE_SUB:
950         case CEE_MUL:
951         case CEE_DIV:
952         case CEE_REM:
953                 /* FIXME: check unverifiable args for STACK_MP */
954                 ins->type = bin_num_table [src1->type] [src2->type];
955                 ins->opcode += binops_op_map [ins->type];
956                 break;
957         case CEE_DIV_UN:
958         case CEE_REM_UN:
959         case CEE_AND:
960         case CEE_OR:
961         case CEE_XOR:
962                 ins->type = bin_int_table [src1->type] [src2->type];
963                 ins->opcode += binops_op_map [ins->type];
964                 break;
965         case CEE_SHL:
966         case CEE_SHR:
967         case CEE_SHR_UN:
968                 ins->type = shift_table [src1->type] [src2->type];
969                 ins->opcode += binops_op_map [ins->type];
970                 break;
971         case OP_COMPARE:
972         case OP_LCOMPARE:
973         case OP_ICOMPARE:
974                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
975                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
976                         ins->opcode = OP_LCOMPARE;
977                 else if (src1->type == STACK_R4)
978                         ins->opcode = OP_RCOMPARE;
979                 else if (src1->type == STACK_R8)
980                         ins->opcode = OP_FCOMPARE;
981                 else
982                         ins->opcode = OP_ICOMPARE;
983                 break;
984         case OP_ICOMPARE_IMM:
985                 ins->type = bin_comp_table [src1->type] [src1->type] ? STACK_I4 : STACK_INV;
986                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
987                         ins->opcode = OP_LCOMPARE_IMM;          
988                 break;
989         case CEE_BEQ:
990         case CEE_BGE:
991         case CEE_BGT:
992         case CEE_BLE:
993         case CEE_BLT:
994         case CEE_BNE_UN:
995         case CEE_BGE_UN:
996         case CEE_BGT_UN:
997         case CEE_BLE_UN:
998         case CEE_BLT_UN:
999                 ins->opcode += beqops_op_map [src1->type];
1000                 break;
1001         case OP_CEQ:
1002                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
1003                 ins->opcode += ceqops_op_map [src1->type];
1004                 break;
1005         case OP_CGT:
1006         case OP_CGT_UN:
1007         case OP_CLT:
1008         case OP_CLT_UN:
1009                 ins->type = (bin_comp_table [src1->type] [src2->type] & 1) ? STACK_I4: STACK_INV;
1010                 ins->opcode += ceqops_op_map [src1->type];
1011                 break;
1012         /* unops */
1013         case CEE_NEG:
1014                 ins->type = neg_table [src1->type];
1015                 ins->opcode += unops_op_map [ins->type];
1016                 break;
1017         case CEE_NOT:
1018                 if (src1->type >= STACK_I4 && src1->type <= STACK_PTR)
1019                         ins->type = src1->type;
1020                 else
1021                         ins->type = STACK_INV;
1022                 ins->opcode += unops_op_map [ins->type];
1023                 break;
1024         case CEE_CONV_I1:
1025         case CEE_CONV_I2:
1026         case CEE_CONV_I4:
1027         case CEE_CONV_U4:
1028                 ins->type = STACK_I4;
1029                 ins->opcode += unops_op_map [src1->type];
1030                 break;
1031         case CEE_CONV_R_UN:
1032                 ins->type = STACK_R8;
1033                 switch (src1->type) {
1034                 case STACK_I4:
1035                 case STACK_PTR:
1036                         ins->opcode = OP_ICONV_TO_R_UN;
1037                         break;
1038                 case STACK_I8:
1039                         ins->opcode = OP_LCONV_TO_R_UN; 
1040                         break;
1041                 }
1042                 break;
1043         case CEE_CONV_OVF_I1:
1044         case CEE_CONV_OVF_U1:
1045         case CEE_CONV_OVF_I2:
1046         case CEE_CONV_OVF_U2:
1047         case CEE_CONV_OVF_I4:
1048         case CEE_CONV_OVF_U4:
1049                 ins->type = STACK_I4;
1050                 ins->opcode += ovf3ops_op_map [src1->type];
1051                 break;
1052         case CEE_CONV_OVF_I_UN:
1053         case CEE_CONV_OVF_U_UN:
1054                 ins->type = STACK_PTR;
1055                 ins->opcode += ovf2ops_op_map [src1->type];
1056                 break;
1057         case CEE_CONV_OVF_I1_UN:
1058         case CEE_CONV_OVF_I2_UN:
1059         case CEE_CONV_OVF_I4_UN:
1060         case CEE_CONV_OVF_U1_UN:
1061         case CEE_CONV_OVF_U2_UN:
1062         case CEE_CONV_OVF_U4_UN:
1063                 ins->type = STACK_I4;
1064                 ins->opcode += ovf2ops_op_map [src1->type];
1065                 break;
1066         case CEE_CONV_U:
1067                 ins->type = STACK_PTR;
1068                 switch (src1->type) {
1069                 case STACK_I4:
1070                         ins->opcode = OP_ICONV_TO_U;
1071                         break;
1072                 case STACK_PTR:
1073                 case STACK_MP:
1074 #if SIZEOF_VOID_P == 8
1075                         ins->opcode = OP_LCONV_TO_U;
1076 #else
1077                         ins->opcode = OP_MOVE;
1078 #endif
1079                         break;
1080                 case STACK_I8:
1081                         ins->opcode = OP_LCONV_TO_U;
1082                         break;
1083                 case STACK_R8:
1084                         ins->opcode = OP_FCONV_TO_U;
1085                         break;
1086                 }
1087                 break;
1088         case CEE_CONV_I8:
1089         case CEE_CONV_U8:
1090                 ins->type = STACK_I8;
1091                 ins->opcode += unops_op_map [src1->type];
1092                 break;
1093         case CEE_CONV_OVF_I8:
1094         case CEE_CONV_OVF_U8:
1095                 ins->type = STACK_I8;
1096                 ins->opcode += ovf3ops_op_map [src1->type];
1097                 break;
1098         case CEE_CONV_OVF_U8_UN:
1099         case CEE_CONV_OVF_I8_UN:
1100                 ins->type = STACK_I8;
1101                 ins->opcode += ovf2ops_op_map [src1->type];
1102                 break;
1103         case CEE_CONV_R4:
1104                 ins->type = cfg->r4_stack_type;
1105                 ins->opcode += unops_op_map [src1->type];
1106                 break;
1107         case CEE_CONV_R8:
1108                 ins->type = STACK_R8;
1109                 ins->opcode += unops_op_map [src1->type];
1110                 break;
1111         case OP_CKFINITE:
1112                 ins->type = STACK_R8;           
1113                 break;
1114         case CEE_CONV_U2:
1115         case CEE_CONV_U1:
1116                 ins->type = STACK_I4;
1117                 ins->opcode += ovfops_op_map [src1->type];
1118                 break;
1119         case CEE_CONV_I:
1120         case CEE_CONV_OVF_I:
1121         case CEE_CONV_OVF_U:
1122                 ins->type = STACK_PTR;
1123                 ins->opcode += ovfops_op_map [src1->type];
1124                 break;
1125         case CEE_ADD_OVF:
1126         case CEE_ADD_OVF_UN:
1127         case CEE_MUL_OVF:
1128         case CEE_MUL_OVF_UN:
1129         case CEE_SUB_OVF:
1130         case CEE_SUB_OVF_UN:
1131                 ins->type = bin_num_table [src1->type] [src2->type];
1132                 ins->opcode += ovfops_op_map [src1->type];
1133                 if (ins->type == STACK_R8)
1134                         ins->type = STACK_INV;
1135                 break;
1136         case OP_LOAD_MEMBASE:
1137                 ins->type = STACK_PTR;
1138                 break;
1139         case OP_LOADI1_MEMBASE:
1140         case OP_LOADU1_MEMBASE:
1141         case OP_LOADI2_MEMBASE:
1142         case OP_LOADU2_MEMBASE:
1143         case OP_LOADI4_MEMBASE:
1144         case OP_LOADU4_MEMBASE:
1145                 ins->type = STACK_PTR;
1146                 break;
1147         case OP_LOADI8_MEMBASE:
1148                 ins->type = STACK_I8;
1149                 break;
1150         case OP_LOADR4_MEMBASE:
1151                 ins->type = cfg->r4_stack_type;
1152                 break;
1153         case OP_LOADR8_MEMBASE:
1154                 ins->type = STACK_R8;
1155                 break;
1156         default:
1157                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1158                 break;
1159         }
1160
1161         if (ins->type == STACK_MP)
1162                 ins->klass = mono_defaults.object_class;
1163 }
1164
1165 static const char 
1166 ldind_type [] = {
1167         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
1168 };
1169
1170 #if 0
1171
1172 static const char
1173 param_table [STACK_MAX] [STACK_MAX] = {
1174         {0},
1175 };
1176
1177 static int
1178 check_values_to_signature (MonoInst *args, MonoType *this_ins, MonoMethodSignature *sig)
1179 {
1180         int i;
1181
1182         if (sig->hasthis) {
1183                 switch (args->type) {
1184                 case STACK_I4:
1185                 case STACK_I8:
1186                 case STACK_R8:
1187                 case STACK_VTYPE:
1188                 case STACK_INV:
1189                         return 0;
1190                 }
1191                 args++;
1192         }
1193         for (i = 0; i < sig->param_count; ++i) {
1194                 switch (args [i].type) {
1195                 case STACK_INV:
1196                         return 0;
1197                 case STACK_MP:
1198                         if (!sig->params [i]->byref)
1199                                 return 0;
1200                         continue;
1201                 case STACK_OBJ:
1202                         if (sig->params [i]->byref)
1203                                 return 0;
1204                         switch (sig->params [i]->type) {
1205                         case MONO_TYPE_CLASS:
1206                         case MONO_TYPE_STRING:
1207                         case MONO_TYPE_OBJECT:
1208                         case MONO_TYPE_SZARRAY:
1209                         case MONO_TYPE_ARRAY:
1210                                 break;
1211                         default:
1212                                 return 0;
1213                         }
1214                         continue;
1215                 case STACK_R8:
1216                         if (sig->params [i]->byref)
1217                                 return 0;
1218                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1219                                 return 0;
1220                         continue;
1221                 case STACK_PTR:
1222                 case STACK_I4:
1223                 case STACK_I8:
1224                 case STACK_VTYPE:
1225                         break;
1226                 }
1227                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1228                         return 0;*/
1229         }
1230         return 1;
1231 }
1232 #endif
1233
1234 /*
1235  * When we need a pointer to the current domain many times in a method, we
1236  * call mono_domain_get() once and we store the result in a local variable.
1237  * This function returns the variable that represents the MonoDomain*.
1238  */
1239 inline static MonoInst *
1240 mono_get_domainvar (MonoCompile *cfg)
1241 {
1242         if (!cfg->domainvar)
1243                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1244         return cfg->domainvar;
1245 }
1246
1247 /*
1248  * The got_var contains the address of the Global Offset Table when AOT 
1249  * compiling.
1250  */
1251 MonoInst *
1252 mono_get_got_var (MonoCompile *cfg)
1253 {
1254         if (!cfg->compile_aot || !cfg->backend->need_got_var)
1255                 return NULL;
1256         if (!cfg->got_var) {
1257                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1258         }
1259         return cfg->got_var;
1260 }
1261
1262 static MonoInst *
1263 mono_get_vtable_var (MonoCompile *cfg)
1264 {
1265         g_assert (cfg->gshared);
1266
1267         if (!cfg->rgctx_var) {
1268                 cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1269                 /* force the var to be stack allocated */
1270                 cfg->rgctx_var->flags |= MONO_INST_VOLATILE;
1271         }
1272
1273         return cfg->rgctx_var;
1274 }
1275
1276 static MonoType*
1277 type_from_stack_type (MonoInst *ins) {
1278         switch (ins->type) {
1279         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1280         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1281         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1282         case STACK_R4: return &mono_defaults.single_class->byval_arg;
1283         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1284         case STACK_MP:
1285                 return &ins->klass->this_arg;
1286         case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1287         case STACK_VTYPE: return &ins->klass->byval_arg;
1288         default:
1289                 g_error ("stack type %d to monotype not handled\n", ins->type);
1290         }
1291         return NULL;
1292 }
1293
1294 static G_GNUC_UNUSED int
1295 type_to_stack_type (MonoCompile *cfg, MonoType *t)
1296 {
1297         t = mono_type_get_underlying_type (t);
1298         switch (t->type) {
1299         case MONO_TYPE_I1:
1300         case MONO_TYPE_U1:
1301         case MONO_TYPE_I2:
1302         case MONO_TYPE_U2:
1303         case MONO_TYPE_I4:
1304         case MONO_TYPE_U4:
1305                 return STACK_I4;
1306         case MONO_TYPE_I:
1307         case MONO_TYPE_U:
1308         case MONO_TYPE_PTR:
1309         case MONO_TYPE_FNPTR:
1310                 return STACK_PTR;
1311         case MONO_TYPE_CLASS:
1312         case MONO_TYPE_STRING:
1313         case MONO_TYPE_OBJECT:
1314         case MONO_TYPE_SZARRAY:
1315         case MONO_TYPE_ARRAY:    
1316                 return STACK_OBJ;
1317         case MONO_TYPE_I8:
1318         case MONO_TYPE_U8:
1319                 return STACK_I8;
1320         case MONO_TYPE_R4:
1321                 return cfg->r4_stack_type;
1322         case MONO_TYPE_R8:
1323                 return STACK_R8;
1324         case MONO_TYPE_VALUETYPE:
1325         case MONO_TYPE_TYPEDBYREF:
1326                 return STACK_VTYPE;
1327         case MONO_TYPE_GENERICINST:
1328                 if (mono_type_generic_inst_is_valuetype (t))
1329                         return STACK_VTYPE;
1330                 else
1331                         return STACK_OBJ;
1332                 break;
1333         default:
1334                 g_assert_not_reached ();
1335         }
1336
1337         return -1;
1338 }
1339
1340 static MonoClass*
1341 array_access_to_klass (int opcode)
1342 {
1343         switch (opcode) {
1344         case CEE_LDELEM_U1:
1345                 return mono_defaults.byte_class;
1346         case CEE_LDELEM_U2:
1347                 return mono_defaults.uint16_class;
1348         case CEE_LDELEM_I:
1349         case CEE_STELEM_I:
1350                 return mono_defaults.int_class;
1351         case CEE_LDELEM_I1:
1352         case CEE_STELEM_I1:
1353                 return mono_defaults.sbyte_class;
1354         case CEE_LDELEM_I2:
1355         case CEE_STELEM_I2:
1356                 return mono_defaults.int16_class;
1357         case CEE_LDELEM_I4:
1358         case CEE_STELEM_I4:
1359                 return mono_defaults.int32_class;
1360         case CEE_LDELEM_U4:
1361                 return mono_defaults.uint32_class;
1362         case CEE_LDELEM_I8:
1363         case CEE_STELEM_I8:
1364                 return mono_defaults.int64_class;
1365         case CEE_LDELEM_R4:
1366         case CEE_STELEM_R4:
1367                 return mono_defaults.single_class;
1368         case CEE_LDELEM_R8:
1369         case CEE_STELEM_R8:
1370                 return mono_defaults.double_class;
1371         case CEE_LDELEM_REF:
1372         case CEE_STELEM_REF:
1373                 return mono_defaults.object_class;
1374         default:
1375                 g_assert_not_reached ();
1376         }
1377         return NULL;
1378 }
1379
1380 /*
1381  * We try to share variables when possible
1382  */
1383 static MonoInst *
1384 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1385 {
1386         MonoInst *res;
1387         int pos, vnum;
1388
1389         /* inlining can result in deeper stacks */ 
1390         if (slot >= cfg->header->max_stack)
1391                 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1392
1393         pos = ins->type - 1 + slot * STACK_MAX;
1394
1395         switch (ins->type) {
1396         case STACK_I4:
1397         case STACK_I8:
1398         case STACK_R8:
1399         case STACK_PTR:
1400         case STACK_MP:
1401         case STACK_OBJ:
1402                 if ((vnum = cfg->intvars [pos]))
1403                         return cfg->varinfo [vnum];
1404                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1405                 cfg->intvars [pos] = res->inst_c0;
1406                 break;
1407         default:
1408                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1409         }
1410         return res;
1411 }
1412
1413 static void
1414 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
1415 {
1416         /* 
1417          * Don't use this if a generic_context is set, since that means AOT can't
1418          * look up the method using just the image+token.
1419          * table == 0 means this is a reference made from a wrapper.
1420          */
1421         if (cfg->compile_aot && !cfg->generic_context && (mono_metadata_token_table (token) > 0)) {
1422                 MonoJumpInfoToken *jump_info_token = (MonoJumpInfoToken *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
1423                 jump_info_token->image = image;
1424                 jump_info_token->token = token;
1425                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
1426         }
1427 }
1428
1429 /*
1430  * This function is called to handle items that are left on the evaluation stack
1431  * at basic block boundaries. What happens is that we save the values to local variables
1432  * and we reload them later when first entering the target basic block (with the
1433  * handle_loaded_temps () function).
1434  * A single joint point will use the same variables (stored in the array bb->out_stack or
1435  * bb->in_stack, if the basic block is before or after the joint point).
1436  *
1437  * This function needs to be called _before_ emitting the last instruction of
1438  * the bb (i.e. before emitting a branch).
1439  * If the stack merge fails at a join point, cfg->unverifiable is set.
1440  */
1441 static void
1442 handle_stack_args (MonoCompile *cfg, MonoInst **sp, int count)
1443 {
1444         int i, bindex;
1445         MonoBasicBlock *bb = cfg->cbb;
1446         MonoBasicBlock *outb;
1447         MonoInst *inst, **locals;
1448         gboolean found;
1449
1450         if (!count)
1451                 return;
1452         if (cfg->verbose_level > 3)
1453                 printf ("%d item(s) on exit from B%d\n", count, bb->block_num);
1454         if (!bb->out_scount) {
1455                 bb->out_scount = count;
1456                 //printf ("bblock %d has out:", bb->block_num);
1457                 found = FALSE;
1458                 for (i = 0; i < bb->out_count; ++i) {
1459                         outb = bb->out_bb [i];
1460                         /* exception handlers are linked, but they should not be considered for stack args */
1461                         if (outb->flags & BB_EXCEPTION_HANDLER)
1462                                 continue;
1463                         //printf (" %d", outb->block_num);
1464                         if (outb->in_stack) {
1465                                 found = TRUE;
1466                                 bb->out_stack = outb->in_stack;
1467                                 break;
1468                         }
1469                 }
1470                 //printf ("\n");
1471                 if (!found) {
1472                         bb->out_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1473                         for (i = 0; i < count; ++i) {
1474                                 /* 
1475                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
1476                                  * stack slot and if they are of the same type.
1477                                  * This won't cause conflicts since if 'local' is used to 
1478                                  * store one of the values in the in_stack of a bblock, then
1479                                  * the same variable will be used for the same outgoing stack 
1480                                  * slot as well. 
1481                                  * This doesn't work when inlining methods, since the bblocks
1482                                  * in the inlined methods do not inherit their in_stack from
1483                                  * the bblock they are inlined to. See bug #58863 for an
1484                                  * example.
1485                                  */
1486                                 if (cfg->inlined_method)
1487                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1488                                 else
1489                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1490                         }
1491                 }
1492         }
1493
1494         for (i = 0; i < bb->out_count; ++i) {
1495                 outb = bb->out_bb [i];
1496                 /* exception handlers are linked, but they should not be considered for stack args */
1497                 if (outb->flags & BB_EXCEPTION_HANDLER)
1498                         continue;
1499                 if (outb->in_scount) {
1500                         if (outb->in_scount != bb->out_scount) {
1501                                 cfg->unverifiable = TRUE;
1502                                 return;
1503                         }
1504                         continue; /* check they are the same locals */
1505                 }
1506                 outb->in_scount = count;
1507                 outb->in_stack = bb->out_stack;
1508         }
1509
1510         locals = bb->out_stack;
1511         cfg->cbb = bb;
1512         for (i = 0; i < count; ++i) {
1513                 EMIT_NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1514                 inst->cil_code = sp [i]->cil_code;
1515                 sp [i] = locals [i];
1516                 if (cfg->verbose_level > 3)
1517                         printf ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
1518         }
1519
1520         /*
1521          * It is possible that the out bblocks already have in_stack assigned, and
1522          * the in_stacks differ. In this case, we will store to all the different 
1523          * in_stacks.
1524          */
1525
1526         found = TRUE;
1527         bindex = 0;
1528         while (found) {
1529                 /* Find a bblock which has a different in_stack */
1530                 found = FALSE;
1531                 while (bindex < bb->out_count) {
1532                         outb = bb->out_bb [bindex];
1533                         /* exception handlers are linked, but they should not be considered for stack args */
1534                         if (outb->flags & BB_EXCEPTION_HANDLER) {
1535                                 bindex++;
1536                                 continue;
1537                         }
1538                         if (outb->in_stack != locals) {
1539                                 for (i = 0; i < count; ++i) {
1540                                         EMIT_NEW_TEMPSTORE (cfg, inst, outb->in_stack [i]->inst_c0, sp [i]);
1541                                         inst->cil_code = sp [i]->cil_code;
1542                                         sp [i] = locals [i];
1543                                         if (cfg->verbose_level > 3)
1544                                                 printf ("storing %d to temp %d\n", i, (int)outb->in_stack [i]->inst_c0);
1545                                 }
1546                                 locals = outb->in_stack;
1547                                 found = TRUE;
1548                                 break;
1549                         }
1550                         bindex ++;
1551                 }
1552         }
1553 }
1554
1555 static MonoInst*
1556 emit_runtime_constant (MonoCompile *cfg, MonoJumpInfoType patch_type, gpointer data)
1557 {
1558         MonoInst *ins;
1559
1560         if (cfg->compile_aot) {
1561                 EMIT_NEW_AOTCONST (cfg, ins, patch_type, data);
1562         } else {
1563                 MonoJumpInfo ji;
1564                 gpointer target;
1565                 MonoError error;
1566
1567                 ji.type = patch_type;
1568                 ji.data.target = data;
1569                 target = mono_resolve_patch_target (NULL, cfg->domain, NULL, &ji, FALSE, &error);
1570                 mono_error_assert_ok (&error);
1571
1572                 EMIT_NEW_PCONST (cfg, ins, target);
1573         }
1574         return ins;
1575 }
1576
1577 static void
1578 mini_emit_interface_bitmap_check (MonoCompile *cfg, int intf_bit_reg, int base_reg, int offset, MonoClass *klass)
1579 {
1580         int ibitmap_reg = alloc_preg (cfg);
1581 #ifdef COMPRESSED_INTERFACE_BITMAP
1582         MonoInst *args [2];
1583         MonoInst *res, *ins;
1584         NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, ibitmap_reg, base_reg, offset);
1585         MONO_ADD_INS (cfg->cbb, ins);
1586         args [0] = ins;
1587         args [1] = emit_runtime_constant (cfg, MONO_PATCH_INFO_IID, klass);
1588         res = mono_emit_jit_icall (cfg, mono_class_interface_match, args);
1589         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, intf_bit_reg, res->dreg);
1590 #else
1591         int ibitmap_byte_reg = alloc_preg (cfg);
1592
1593         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, base_reg, offset);
1594
1595         if (cfg->compile_aot) {
1596                 int iid_reg = alloc_preg (cfg);
1597                 int shifted_iid_reg = alloc_preg (cfg);
1598                 int ibitmap_byte_address_reg = alloc_preg (cfg);
1599                 int masked_iid_reg = alloc_preg (cfg);
1600                 int iid_one_bit_reg = alloc_preg (cfg);
1601                 int iid_bit_reg = alloc_preg (cfg);
1602                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1603                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, shifted_iid_reg, iid_reg, 3);
1604                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ibitmap_byte_address_reg, ibitmap_reg, shifted_iid_reg);
1605                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, ibitmap_byte_reg, ibitmap_byte_address_reg, 0);
1606                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, masked_iid_reg, iid_reg, 7);
1607                 MONO_EMIT_NEW_ICONST (cfg, iid_one_bit_reg, 1);
1608                 MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg);
1609                 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg);
1610         } else {
1611                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
1612                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
1613         }
1614 #endif
1615 }
1616
1617 /* 
1618  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
1619  * stored in "klass_reg" implements the interface "klass".
1620  */
1621 static void
1622 mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass)
1623 {
1624         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, interface_bitmap), klass);
1625 }
1626
1627 /* 
1628  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoVTable
1629  * stored in "vtable_reg" implements the interface "klass".
1630  */
1631 static void
1632 mini_emit_load_intf_bit_reg_vtable (MonoCompile *cfg, int intf_bit_reg, int vtable_reg, MonoClass *klass)
1633 {
1634         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, interface_bitmap), klass);
1635 }
1636
1637 /* 
1638  * Emit code which checks whenever the interface id of @klass is smaller than
1639  * than the value given by max_iid_reg.
1640 */
1641 static void
1642 mini_emit_max_iid_check (MonoCompile *cfg, int max_iid_reg, MonoClass *klass,
1643                                                  MonoBasicBlock *false_target)
1644 {
1645         if (cfg->compile_aot) {
1646                 int iid_reg = alloc_preg (cfg);
1647                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1648                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, max_iid_reg, iid_reg);
1649         }
1650         else
1651                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, max_iid_reg, klass->interface_id);
1652         if (false_target)
1653                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1654         else
1655                 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1656 }
1657
1658 /* Same as above, but obtains max_iid from a vtable */
1659 static void
1660 mini_emit_max_iid_check_vtable (MonoCompile *cfg, int vtable_reg, MonoClass *klass,
1661                                                                  MonoBasicBlock *false_target)
1662 {
1663         int max_iid_reg = alloc_preg (cfg);
1664                 
1665         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU4_MEMBASE, max_iid_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, max_interface_id));
1666         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1667 }
1668
1669 /* Same as above, but obtains max_iid from a klass */
1670 static void
1671 mini_emit_max_iid_check_class (MonoCompile *cfg, int klass_reg, MonoClass *klass,
1672                                                                  MonoBasicBlock *false_target)
1673 {
1674         int max_iid_reg = alloc_preg (cfg);
1675
1676         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU4_MEMBASE, max_iid_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, max_interface_id));
1677         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1678 }
1679
1680 static void
1681 mini_emit_isninst_cast_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_ins, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1682 {
1683         int idepth_reg = alloc_preg (cfg);
1684         int stypes_reg = alloc_preg (cfg);
1685         int stype = alloc_preg (cfg);
1686
1687         mono_class_setup_supertypes (klass);
1688
1689         if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1690                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1691                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1692                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1693         }
1694         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1695         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1696         if (klass_ins) {
1697                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, klass_ins->dreg);
1698         } else if (cfg->compile_aot) {
1699                 int const_reg = alloc_preg (cfg);
1700                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1701                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, const_reg);
1702         } else {
1703                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, stype, klass);
1704         }
1705         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, true_target);
1706 }
1707
1708 static void
1709 mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1710 {
1711         mini_emit_isninst_cast_inst (cfg, klass_reg, klass, NULL, false_target, true_target);
1712 }
1713
1714 static void
1715 mini_emit_iface_cast (MonoCompile *cfg, int vtable_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1716 {
1717         int intf_reg = alloc_preg (cfg);
1718
1719         mini_emit_max_iid_check_vtable (cfg, vtable_reg, klass, false_target);
1720         mini_emit_load_intf_bit_reg_vtable (cfg, intf_reg, vtable_reg, klass);
1721         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_reg, 0);
1722         if (true_target)
1723                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1724         else
1725                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");               
1726 }
1727
1728 /*
1729  * Variant of the above that takes a register to the class, not the vtable.
1730  */
1731 static void
1732 mini_emit_iface_class_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1733 {
1734         int intf_bit_reg = alloc_preg (cfg);
1735
1736         mini_emit_max_iid_check_class (cfg, klass_reg, klass, false_target);
1737         mini_emit_load_intf_bit_reg_class (cfg, intf_bit_reg, klass_reg, klass);
1738         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_bit_reg, 0);
1739         if (true_target)
1740                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1741         else
1742                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
1743 }
1744
1745 static inline void
1746 mini_emit_class_check_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_inst)
1747 {
1748         if (klass_inst) {
1749                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_inst->dreg);
1750         } else {
1751                 MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
1752                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, ins->dreg);
1753         }
1754         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1755 }
1756
1757 static inline void
1758 mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
1759 {
1760         mini_emit_class_check_inst (cfg, klass_reg, klass, NULL);
1761 }
1762
1763 static inline void
1764 mini_emit_class_check_branch (MonoCompile *cfg, int klass_reg, MonoClass *klass, int branch_op, MonoBasicBlock *target)
1765 {
1766         if (cfg->compile_aot) {
1767                 int const_reg = alloc_preg (cfg);
1768                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1769                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1770         } else {
1771                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1772         }
1773         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, branch_op, target);
1774 }
1775
1776 static void
1777 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null);
1778         
1779 static void
1780 mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoInst *klass_inst, MonoBasicBlock *object_is_null)
1781 {
1782         if (klass->rank) {
1783                 int rank_reg = alloc_preg (cfg);
1784                 int eclass_reg = alloc_preg (cfg);
1785
1786                 g_assert (!klass_inst);
1787                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, rank));
1788                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
1789                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1790                 //              MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
1791                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
1792                 if (klass->cast_class == mono_defaults.object_class) {
1793                         int parent_reg = alloc_preg (cfg);
1794                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
1795                         mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, object_is_null);
1796                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1797                 } else if (klass->cast_class == mono_defaults.enum_class->parent) {
1798                         mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, object_is_null);
1799                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1800                 } else if (klass->cast_class == mono_defaults.enum_class) {
1801                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1802                 } else if (mono_class_is_interface (klass->cast_class)) {
1803                         mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, NULL, NULL);
1804                 } else {
1805                         // Pass -1 as obj_reg to skip the check below for arrays of arrays
1806                         mini_emit_castclass (cfg, -1, eclass_reg, klass->cast_class, object_is_null);
1807                 }
1808
1809                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY) && (obj_reg != -1)) {
1810                         /* Check that the object is a vector too */
1811                         int bounds_reg = alloc_preg (cfg);
1812                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
1813                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
1814                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1815                 }
1816         } else {
1817                 int idepth_reg = alloc_preg (cfg);
1818                 int stypes_reg = alloc_preg (cfg);
1819                 int stype = alloc_preg (cfg);
1820
1821                 mono_class_setup_supertypes (klass);
1822
1823                 if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1824                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1825                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1826                         MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1827                 }
1828                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1829                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1830                 mini_emit_class_check_inst (cfg, stype, klass, klass_inst);
1831         }
1832 }
1833
1834 static void
1835 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null)
1836 {
1837         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, NULL, object_is_null);
1838 }
1839
1840 static void 
1841 mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
1842 {
1843         int val_reg;
1844
1845         g_assert (val == 0);
1846
1847         if (align == 0)
1848                 align = 4;
1849
1850         if ((size <= SIZEOF_REGISTER) && (size <= align)) {
1851                 switch (size) {
1852                 case 1:
1853                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, destreg, offset, val);
1854                         return;
1855                 case 2:
1856                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI2_MEMBASE_IMM, destreg, offset, val);
1857                         return;
1858                 case 4:
1859                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, destreg, offset, val);
1860                         return;
1861 #if SIZEOF_REGISTER == 8
1862                 case 8:
1863                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI8_MEMBASE_IMM, destreg, offset, val);
1864                         return;
1865 #endif
1866                 }
1867         }
1868
1869         val_reg = alloc_preg (cfg);
1870
1871         if (SIZEOF_REGISTER == 8)
1872                 MONO_EMIT_NEW_I8CONST (cfg, val_reg, val);
1873         else
1874                 MONO_EMIT_NEW_ICONST (cfg, val_reg, val);
1875
1876         if (align < 4) {
1877                 /* This could be optimized further if neccesary */
1878                 while (size >= 1) {
1879                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1880                         offset += 1;
1881                         size -= 1;
1882                 }
1883                 return;
1884         }       
1885
1886         if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
1887                 if (offset % 8) {
1888                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1889                         offset += 4;
1890                         size -= 4;
1891                 }
1892                 while (size >= 8) {
1893                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, offset, val_reg);
1894                         offset += 8;
1895                         size -= 8;
1896                 }
1897         }       
1898
1899         while (size >= 4) {
1900                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1901                 offset += 4;
1902                 size -= 4;
1903         }
1904         while (size >= 2) {
1905                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg);
1906                 offset += 2;
1907                 size -= 2;
1908         }
1909         while (size >= 1) {
1910                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1911                 offset += 1;
1912                 size -= 1;
1913         }
1914 }
1915
1916 void 
1917 mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
1918 {
1919         int cur_reg;
1920
1921         if (align == 0)
1922                 align = 4;
1923
1924         /*FIXME arbitrary hack to avoid unbound code expansion.*/
1925         g_assert (size < 10000);
1926
1927         if (align < 4) {
1928                 /* This could be optimized further if neccesary */
1929                 while (size >= 1) {
1930                         cur_reg = alloc_preg (cfg);
1931                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1932                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1933                         doffset += 1;
1934                         soffset += 1;
1935                         size -= 1;
1936                 }
1937         }
1938
1939         if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
1940                 while (size >= 8) {
1941                         cur_reg = alloc_preg (cfg);
1942                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI8_MEMBASE, cur_reg, srcreg, soffset);
1943                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, doffset, cur_reg);
1944                         doffset += 8;
1945                         soffset += 8;
1946                         size -= 8;
1947                 }
1948         }       
1949
1950         while (size >= 4) {
1951                 cur_reg = alloc_preg (cfg);
1952                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, cur_reg, srcreg, soffset);
1953                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, doffset, cur_reg);
1954                 doffset += 4;
1955                 soffset += 4;
1956                 size -= 4;
1957         }
1958         while (size >= 2) {
1959                 cur_reg = alloc_preg (cfg);
1960                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, cur_reg, srcreg, soffset);
1961                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, doffset, cur_reg);
1962                 doffset += 2;
1963                 soffset += 2;
1964                 size -= 2;
1965         }
1966         while (size >= 1) {
1967                 cur_reg = alloc_preg (cfg);
1968                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1969                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1970                 doffset += 1;
1971                 soffset += 1;
1972                 size -= 1;
1973         }
1974 }
1975
1976 static void
1977 emit_tls_set (MonoCompile *cfg, int sreg1, MonoTlsKey tls_key)
1978 {
1979         MonoInst *ins, *c;
1980
1981         if (cfg->compile_aot) {
1982                 EMIT_NEW_TLS_OFFSETCONST (cfg, c, tls_key);
1983                 MONO_INST_NEW (cfg, ins, OP_TLS_SET_REG);
1984                 ins->sreg1 = sreg1;
1985                 ins->sreg2 = c->dreg;
1986                 MONO_ADD_INS (cfg->cbb, ins);
1987         } else {
1988                 MONO_INST_NEW (cfg, ins, OP_TLS_SET);
1989                 ins->sreg1 = sreg1;
1990                 ins->inst_offset = mini_get_tls_offset (tls_key);
1991                 MONO_ADD_INS (cfg->cbb, ins);
1992         }
1993 }
1994
1995 /*
1996  * emit_push_lmf:
1997  *
1998  *   Emit IR to push the current LMF onto the LMF stack.
1999  */
2000 static void
2001 emit_push_lmf (MonoCompile *cfg)
2002 {
2003         /*
2004          * Emit IR to push the LMF:
2005          * lmf_addr = <lmf_addr from tls>
2006          * lmf->lmf_addr = lmf_addr
2007          * lmf->prev_lmf = *lmf_addr
2008          * *lmf_addr = lmf
2009          */
2010         int lmf_reg, prev_lmf_reg;
2011         MonoInst *ins, *lmf_ins;
2012
2013         if (!cfg->lmf_ir)
2014                 return;
2015
2016         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
2017                 /* Load current lmf */
2018                 lmf_ins = mono_get_lmf_intrinsic (cfg);
2019                 g_assert (lmf_ins);
2020                 MONO_ADD_INS (cfg->cbb, lmf_ins);
2021                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2022                 lmf_reg = ins->dreg;
2023                 /* Save previous_lmf */
2024                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), lmf_ins->dreg);
2025                 /* Set new LMF */
2026                 emit_tls_set (cfg, lmf_reg, TLS_KEY_LMF);
2027         } else {
2028                 /*
2029                  * Store lmf_addr in a variable, so it can be allocated to a global register.
2030                  */
2031                 if (!cfg->lmf_addr_var)
2032                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2033
2034 #ifdef HOST_WIN32
2035                 ins = mono_get_jit_tls_intrinsic (cfg);
2036                 if (ins) {
2037                         int jit_tls_dreg = ins->dreg;
2038
2039                         MONO_ADD_INS (cfg->cbb, ins);
2040                         lmf_reg = alloc_preg (cfg);
2041                         EMIT_NEW_BIALU_IMM (cfg, lmf_ins, OP_PADD_IMM, lmf_reg, jit_tls_dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2042                 } else {
2043                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2044                 }
2045 #else
2046                 lmf_ins = mono_get_lmf_addr_intrinsic (cfg);
2047                 if (lmf_ins) {
2048                         MONO_ADD_INS (cfg->cbb, lmf_ins);
2049                 } else {
2050 #ifdef TARGET_IOS
2051                         MonoInst *args [16], *jit_tls_ins, *ins;
2052
2053                         /* Inline mono_get_lmf_addr () */
2054                         /* jit_tls = pthread_getspecific (mono_jit_tls_id); lmf_addr = &jit_tls->lmf; */
2055
2056                         /* Load mono_jit_tls_id */
2057                         if (cfg->compile_aot)
2058                                 EMIT_NEW_AOTCONST (cfg, args [0], MONO_PATCH_INFO_JIT_TLS_ID, NULL);
2059                         else
2060                                 EMIT_NEW_ICONST (cfg, args [0], mono_jit_tls_id);
2061                         /* call pthread_getspecific () */
2062                         jit_tls_ins = mono_emit_jit_icall (cfg, pthread_getspecific, args);
2063                         /* lmf_addr = &jit_tls->lmf */
2064                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, cfg->lmf_addr_var->dreg, jit_tls_ins->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2065                         lmf_ins = ins;
2066 #else
2067                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2068 #endif
2069                 }
2070 #endif
2071                 lmf_ins->dreg = cfg->lmf_addr_var->dreg;
2072
2073                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2074                 lmf_reg = ins->dreg;
2075
2076                 prev_lmf_reg = alloc_preg (cfg);
2077                 /* Save previous_lmf */
2078                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, cfg->lmf_addr_var->dreg, 0);
2079                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), prev_lmf_reg);
2080                 /* Set new lmf */
2081                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, cfg->lmf_addr_var->dreg, 0, lmf_reg);
2082         }
2083 }
2084
2085 /*
2086  * emit_pop_lmf:
2087  *
2088  *   Emit IR to pop the current LMF from the LMF stack.
2089  */
2090 static void
2091 emit_pop_lmf (MonoCompile *cfg)
2092 {
2093         int lmf_reg, lmf_addr_reg, prev_lmf_reg;
2094         MonoInst *ins;
2095
2096         if (!cfg->lmf_ir)
2097                 return;
2098
2099         EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2100         lmf_reg = ins->dreg;
2101
2102         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
2103                 /* Load previous_lmf */
2104                 prev_lmf_reg = alloc_preg (cfg);
2105                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2106                 /* Set new LMF */
2107                 emit_tls_set (cfg, prev_lmf_reg, TLS_KEY_LMF);
2108         } else {
2109                 /*
2110                  * Emit IR to pop the LMF:
2111                  * *(lmf->lmf_addr) = lmf->prev_lmf
2112                  */
2113                 /* This could be called before emit_push_lmf () */
2114                 if (!cfg->lmf_addr_var)
2115                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2116                 lmf_addr_reg = cfg->lmf_addr_var->dreg;
2117
2118                 prev_lmf_reg = alloc_preg (cfg);
2119                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2120                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, prev_lmf_reg);
2121         }
2122 }
2123
2124 static void
2125 emit_instrumentation_call (MonoCompile *cfg, void *func)
2126 {
2127         MonoInst *iargs [1];
2128
2129         /*
2130          * Avoid instrumenting inlined methods since it can
2131          * distort profiling results.
2132          */
2133         if (cfg->method != cfg->current_method)
2134                 return;
2135
2136         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
2137                 EMIT_NEW_METHODCONST (cfg, iargs [0], cfg->method);
2138                 mono_emit_jit_icall (cfg, func, iargs);
2139         }
2140 }
2141
2142 static int
2143 ret_type_to_call_opcode (MonoCompile *cfg, MonoType *type, int calli, int virt)
2144 {
2145 handle_enum:
2146         type = mini_get_underlying_type (type);
2147         switch (type->type) {
2148         case MONO_TYPE_VOID:
2149                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALL_MEMBASE: OP_VOIDCALL;
2150         case MONO_TYPE_I1:
2151         case MONO_TYPE_U1:
2152         case MONO_TYPE_I2:
2153         case MONO_TYPE_U2:
2154         case MONO_TYPE_I4:
2155         case MONO_TYPE_U4:
2156                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2157         case MONO_TYPE_I:
2158         case MONO_TYPE_U:
2159         case MONO_TYPE_PTR:
2160         case MONO_TYPE_FNPTR:
2161                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2162         case MONO_TYPE_CLASS:
2163         case MONO_TYPE_STRING:
2164         case MONO_TYPE_OBJECT:
2165         case MONO_TYPE_SZARRAY:
2166         case MONO_TYPE_ARRAY:    
2167                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2168         case MONO_TYPE_I8:
2169         case MONO_TYPE_U8:
2170                 return calli? OP_LCALL_REG: virt? OP_LCALL_MEMBASE: OP_LCALL;
2171         case MONO_TYPE_R4:
2172                 if (cfg->r4fp)
2173                         return calli? OP_RCALL_REG: virt? OP_RCALL_MEMBASE: OP_RCALL;
2174                 else
2175                         return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2176         case MONO_TYPE_R8:
2177                 return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2178         case MONO_TYPE_VALUETYPE:
2179                 if (type->data.klass->enumtype) {
2180                         type = mono_class_enum_basetype (type->data.klass);
2181                         goto handle_enum;
2182                 } else
2183                         return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2184         case MONO_TYPE_TYPEDBYREF:
2185                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2186         case MONO_TYPE_GENERICINST:
2187                 type = &type->data.generic_class->container_class->byval_arg;
2188                 goto handle_enum;
2189         case MONO_TYPE_VAR:
2190         case MONO_TYPE_MVAR:
2191                 /* gsharedvt */
2192                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2193         default:
2194                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
2195         }
2196         return -1;
2197 }
2198
2199 //XXX this ignores if t is byref
2200 #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)))))
2201
2202 /*
2203  * target_type_is_incompatible:
2204  * @cfg: MonoCompile context
2205  *
2206  * Check that the item @arg on the evaluation stack can be stored
2207  * in the target type (can be a local, or field, etc).
2208  * The cfg arg can be used to check if we need verification or just
2209  * validity checks.
2210  *
2211  * Returns: non-0 value if arg can't be stored on a target.
2212  */
2213 static int
2214 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
2215 {
2216         MonoType *simple_type;
2217         MonoClass *klass;
2218
2219         if (target->byref) {
2220                 /* FIXME: check that the pointed to types match */
2221                 if (arg->type == STACK_MP) {
2222                         /* This is needed to handle gshared types + ldaddr. We lower the types so we can handle enums and other typedef-like types. */
2223                         MonoClass *target_class_lowered = mono_class_from_mono_type (mini_get_underlying_type (&mono_class_from_mono_type (target)->byval_arg));
2224                         MonoClass *source_class_lowered = mono_class_from_mono_type (mini_get_underlying_type (&arg->klass->byval_arg));
2225
2226                         /* if the target is native int& or same type */
2227                         if (target->type == MONO_TYPE_I || target_class_lowered == source_class_lowered)
2228                                 return 0;
2229
2230                         /* Both are primitive type byrefs and the source points to a larger type that the destination */
2231                         if (MONO_TYPE_IS_PRIMITIVE_SCALAR (&target_class_lowered->byval_arg) && MONO_TYPE_IS_PRIMITIVE_SCALAR (&source_class_lowered->byval_arg) &&
2232                                 mono_class_instance_size (target_class_lowered) <= mono_class_instance_size (source_class_lowered))
2233                                 return 0;
2234                         return 1;
2235                 }
2236                 if (arg->type == STACK_PTR)
2237                         return 0;
2238                 return 1;
2239         }
2240
2241         simple_type = mini_get_underlying_type (target);
2242         switch (simple_type->type) {
2243         case MONO_TYPE_VOID:
2244                 return 1;
2245         case MONO_TYPE_I1:
2246         case MONO_TYPE_U1:
2247         case MONO_TYPE_I2:
2248         case MONO_TYPE_U2:
2249         case MONO_TYPE_I4:
2250         case MONO_TYPE_U4:
2251                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2252                         return 1;
2253                 return 0;
2254         case MONO_TYPE_PTR:
2255                 /* STACK_MP is needed when setting pinned locals */
2256                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2257                         return 1;
2258                 return 0;
2259         case MONO_TYPE_I:
2260         case MONO_TYPE_U:
2261         case MONO_TYPE_FNPTR:
2262                 /* 
2263                  * Some opcodes like ldloca returns 'transient pointers' which can be stored in
2264                  * in native int. (#688008).
2265                  */
2266                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2267                         return 1;
2268                 return 0;
2269         case MONO_TYPE_CLASS:
2270         case MONO_TYPE_STRING:
2271         case MONO_TYPE_OBJECT:
2272         case MONO_TYPE_SZARRAY:
2273         case MONO_TYPE_ARRAY:    
2274                 if (arg->type != STACK_OBJ)
2275                         return 1;
2276                 /* FIXME: check type compatibility */
2277                 return 0;
2278         case MONO_TYPE_I8:
2279         case MONO_TYPE_U8:
2280                 if (arg->type != STACK_I8)
2281                         return 1;
2282                 return 0;
2283         case MONO_TYPE_R4:
2284                 if (arg->type != cfg->r4_stack_type)
2285                         return 1;
2286                 return 0;
2287         case MONO_TYPE_R8:
2288                 if (arg->type != STACK_R8)
2289                         return 1;
2290                 return 0;
2291         case MONO_TYPE_VALUETYPE:
2292                 if (arg->type != STACK_VTYPE)
2293                         return 1;
2294                 klass = mono_class_from_mono_type (simple_type);
2295                 if (klass != arg->klass)
2296                         return 1;
2297                 return 0;
2298         case MONO_TYPE_TYPEDBYREF:
2299                 if (arg->type != STACK_VTYPE)
2300                         return 1;
2301                 klass = mono_class_from_mono_type (simple_type);
2302                 if (klass != arg->klass)
2303                         return 1;
2304                 return 0;
2305         case MONO_TYPE_GENERICINST:
2306                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2307                         MonoClass *target_class;
2308                         if (arg->type != STACK_VTYPE)
2309                                 return 1;
2310                         klass = mono_class_from_mono_type (simple_type);
2311                         target_class = mono_class_from_mono_type (target);
2312                         /* The second cases is needed when doing partial sharing */
2313                         if (klass != arg->klass && target_class != arg->klass && target_class != mono_class_from_mono_type (mini_get_underlying_type (&arg->klass->byval_arg)))
2314                                 return 1;
2315                         return 0;
2316                 } else {
2317                         if (arg->type != STACK_OBJ)
2318                                 return 1;
2319                         /* FIXME: check type compatibility */
2320                         return 0;
2321                 }
2322         case MONO_TYPE_VAR:
2323         case MONO_TYPE_MVAR:
2324                 g_assert (cfg->gshared);
2325                 if (mini_type_var_is_vt (simple_type)) {
2326                         if (arg->type != STACK_VTYPE)
2327                                 return 1;
2328                 } else {
2329                         if (arg->type != STACK_OBJ)
2330                                 return 1;
2331                 }
2332                 return 0;
2333         default:
2334                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2335         }
2336         return 1;
2337 }
2338
2339 /*
2340  * Prepare arguments for passing to a function call.
2341  * Return a non-zero value if the arguments can't be passed to the given
2342  * signature.
2343  * The type checks are not yet complete and some conversions may need
2344  * casts on 32 or 64 bit architectures.
2345  *
2346  * FIXME: implement this using target_type_is_incompatible ()
2347  */
2348 static int
2349 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2350 {
2351         MonoType *simple_type;
2352         int i;
2353
2354         if (sig->hasthis) {
2355                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2356                         return 1;
2357                 args++;
2358         }
2359         for (i = 0; i < sig->param_count; ++i) {
2360                 if (sig->params [i]->byref) {
2361                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2362                                 return 1;
2363                         continue;
2364                 }
2365                 simple_type = mini_get_underlying_type (sig->params [i]);
2366 handle_enum:
2367                 switch (simple_type->type) {
2368                 case MONO_TYPE_VOID:
2369                         return 1;
2370                         continue;
2371                 case MONO_TYPE_I1:
2372                 case MONO_TYPE_U1:
2373                 case MONO_TYPE_I2:
2374                 case MONO_TYPE_U2:
2375                 case MONO_TYPE_I4:
2376                 case MONO_TYPE_U4:
2377                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2378                                 return 1;
2379                         continue;
2380                 case MONO_TYPE_I:
2381                 case MONO_TYPE_U:
2382                 case MONO_TYPE_PTR:
2383                 case MONO_TYPE_FNPTR:
2384                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2385                                 return 1;
2386                         continue;
2387                 case MONO_TYPE_CLASS:
2388                 case MONO_TYPE_STRING:
2389                 case MONO_TYPE_OBJECT:
2390                 case MONO_TYPE_SZARRAY:
2391                 case MONO_TYPE_ARRAY:    
2392                         if (args [i]->type != STACK_OBJ)
2393                                 return 1;
2394                         continue;
2395                 case MONO_TYPE_I8:
2396                 case MONO_TYPE_U8:
2397                         if (args [i]->type != STACK_I8)
2398                                 return 1;
2399                         continue;
2400                 case MONO_TYPE_R4:
2401                         if (args [i]->type != cfg->r4_stack_type)
2402                                 return 1;
2403                         continue;
2404                 case MONO_TYPE_R8:
2405                         if (args [i]->type != STACK_R8)
2406                                 return 1;
2407                         continue;
2408                 case MONO_TYPE_VALUETYPE:
2409                         if (simple_type->data.klass->enumtype) {
2410                                 simple_type = mono_class_enum_basetype (simple_type->data.klass);
2411                                 goto handle_enum;
2412                         }
2413                         if (args [i]->type != STACK_VTYPE)
2414                                 return 1;
2415                         continue;
2416                 case MONO_TYPE_TYPEDBYREF:
2417                         if (args [i]->type != STACK_VTYPE)
2418                                 return 1;
2419                         continue;
2420                 case MONO_TYPE_GENERICINST:
2421                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2422                         goto handle_enum;
2423                 case MONO_TYPE_VAR:
2424                 case MONO_TYPE_MVAR:
2425                         /* gsharedvt */
2426                         if (args [i]->type != STACK_VTYPE)
2427                                 return 1;
2428                         continue;
2429                 default:
2430                         g_error ("unknown type 0x%02x in check_call_signature",
2431                                  simple_type->type);
2432                 }
2433         }
2434         return 0;
2435 }
2436
2437 static int
2438 callvirt_to_call (int opcode)
2439 {
2440         switch (opcode) {
2441         case OP_CALL_MEMBASE:
2442                 return OP_CALL;
2443         case OP_VOIDCALL_MEMBASE:
2444                 return OP_VOIDCALL;
2445         case OP_FCALL_MEMBASE:
2446                 return OP_FCALL;
2447         case OP_RCALL_MEMBASE:
2448                 return OP_RCALL;
2449         case OP_VCALL_MEMBASE:
2450                 return OP_VCALL;
2451         case OP_LCALL_MEMBASE:
2452                 return OP_LCALL;
2453         default:
2454                 g_assert_not_reached ();
2455         }
2456
2457         return -1;
2458 }
2459
2460 static int
2461 callvirt_to_call_reg (int opcode)
2462 {
2463         switch (opcode) {
2464         case OP_CALL_MEMBASE:
2465                 return OP_CALL_REG;
2466         case OP_VOIDCALL_MEMBASE:
2467                 return OP_VOIDCALL_REG;
2468         case OP_FCALL_MEMBASE:
2469                 return OP_FCALL_REG;
2470         case OP_RCALL_MEMBASE:
2471                 return OP_RCALL_REG;
2472         case OP_VCALL_MEMBASE:
2473                 return OP_VCALL_REG;
2474         case OP_LCALL_MEMBASE:
2475                 return OP_LCALL_REG;
2476         default:
2477                 g_assert_not_reached ();
2478         }
2479
2480         return -1;
2481 }
2482
2483 /* Either METHOD or IMT_ARG needs to be set */
2484 static void
2485 emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoMethod *method, MonoInst *imt_arg)
2486 {
2487         int method_reg;
2488
2489         if (COMPILE_LLVM (cfg)) {
2490                 if (imt_arg) {
2491                         method_reg = alloc_preg (cfg);
2492                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2493                 } else {
2494                         MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
2495                         method_reg = ins->dreg;
2496                 }
2497
2498 #ifdef ENABLE_LLVM
2499                 call->imt_arg_reg = method_reg;
2500 #endif
2501                 mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2502                 return;
2503         }
2504
2505         if (imt_arg) {
2506                 method_reg = alloc_preg (cfg);
2507                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2508         } else {
2509                 MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
2510                 method_reg = ins->dreg;
2511         }
2512
2513         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2514 }
2515
2516 static MonoJumpInfo *
2517 mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpointer target)
2518 {
2519         MonoJumpInfo *ji = (MonoJumpInfo *)mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
2520
2521         ji->ip.i = ip;
2522         ji->type = type;
2523         ji->data.target = target;
2524
2525         return ji;
2526 }
2527
2528 static int
2529 mini_class_check_context_used (MonoCompile *cfg, MonoClass *klass)
2530 {
2531         if (cfg->gshared)
2532                 return mono_class_check_context_used (klass);
2533         else
2534                 return 0;
2535 }
2536
2537 static int
2538 mini_method_check_context_used (MonoCompile *cfg, MonoMethod *method)
2539 {
2540         if (cfg->gshared)
2541                 return mono_method_check_context_used (method);
2542         else
2543                 return 0;
2544 }
2545
2546 /*
2547  * check_method_sharing:
2548  *
2549  *   Check whenever the vtable or an mrgctx needs to be passed when calling CMETHOD.
2550  */
2551 static void
2552 check_method_sharing (MonoCompile *cfg, MonoMethod *cmethod, gboolean *out_pass_vtable, gboolean *out_pass_mrgctx)
2553 {
2554         gboolean pass_vtable = FALSE;
2555         gboolean pass_mrgctx = FALSE;
2556
2557         if (((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
2558                 (mono_class_is_ginst (cmethod->klass) || mono_class_is_gtd (cmethod->klass))) {
2559                 gboolean sharable = FALSE;
2560
2561                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE))
2562                         sharable = TRUE;
2563
2564                 /*
2565                  * Pass vtable iff target method might
2566                  * be shared, which means that sharing
2567                  * is enabled for its class and its
2568                  * context is sharable (and it's not a
2569                  * generic method).
2570                  */
2571                 if (sharable && !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
2572                         pass_vtable = TRUE;
2573         }
2574
2575         if (mini_method_get_context (cmethod) &&
2576                 mini_method_get_context (cmethod)->method_inst) {
2577                 g_assert (!pass_vtable);
2578
2579                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE)) {
2580                         pass_mrgctx = TRUE;
2581                 } else {
2582                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (mono_method_signature (cmethod)))
2583                                 pass_mrgctx = TRUE;
2584                 }
2585         }
2586
2587         if (out_pass_vtable)
2588                 *out_pass_vtable = pass_vtable;
2589         if (out_pass_mrgctx)
2590                 *out_pass_mrgctx = pass_mrgctx;
2591 }
2592
2593 inline static MonoCallInst *
2594 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
2595                                          MonoInst **args, int calli, int virtual_, int tail, int rgctx, int unbox_trampoline)
2596 {
2597         MonoType *sig_ret;
2598         MonoCallInst *call;
2599 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2600         int i;
2601 #endif
2602
2603         if (cfg->llvm_only)
2604                 tail = FALSE;
2605
2606         if (tail) {
2607                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
2608
2609                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
2610         } else
2611                 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (cfg, sig->ret, calli, virtual_));
2612
2613         call->args = args;
2614         call->signature = sig;
2615         call->rgctx_reg = rgctx;
2616         sig_ret = mini_get_underlying_type (sig->ret);
2617
2618         type_to_eval_stack_type ((cfg), sig_ret, &call->inst);
2619
2620         if (tail) {
2621                 if (mini_type_is_vtype (sig_ret)) {
2622                         call->vret_var = cfg->vret_addr;
2623                         //g_assert_not_reached ();
2624                 }
2625         } else if (mini_type_is_vtype (sig_ret)) {
2626                 MonoInst *temp = mono_compile_create_var (cfg, sig_ret, OP_LOCAL);
2627                 MonoInst *loada;
2628
2629                 temp->backend.is_pinvoke = sig->pinvoke;
2630
2631                 /*
2632                  * We use a new opcode OP_OUTARG_VTRETADDR instead of LDADDR for emitting the
2633                  * address of return value to increase optimization opportunities.
2634                  * Before vtype decomposition, the dreg of the call ins itself represents the
2635                  * fact the call modifies the return value. After decomposition, the call will
2636                  * be transformed into one of the OP_VOIDCALL opcodes, and the VTRETADDR opcode
2637                  * will be transformed into an LDADDR.
2638                  */
2639                 MONO_INST_NEW (cfg, loada, OP_OUTARG_VTRETADDR);
2640                 loada->dreg = alloc_preg (cfg);
2641                 loada->inst_p0 = temp;
2642                 /* We reference the call too since call->dreg could change during optimization */
2643                 loada->inst_p1 = call;
2644                 MONO_ADD_INS (cfg->cbb, loada);
2645
2646                 call->inst.dreg = temp->dreg;
2647
2648                 call->vret_var = loada;
2649         } else if (!MONO_TYPE_IS_VOID (sig_ret))
2650                 call->inst.dreg = alloc_dreg (cfg, (MonoStackType)call->inst.type);
2651
2652 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2653         if (COMPILE_SOFT_FLOAT (cfg)) {
2654                 /* 
2655                  * If the call has a float argument, we would need to do an r8->r4 conversion using 
2656                  * an icall, but that cannot be done during the call sequence since it would clobber
2657                  * the call registers + the stack. So we do it before emitting the call.
2658                  */
2659                 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2660                         MonoType *t;
2661                         MonoInst *in = call->args [i];
2662
2663                         if (i >= sig->hasthis)
2664                                 t = sig->params [i - sig->hasthis];
2665                         else
2666                                 t = &mono_defaults.int_class->byval_arg;
2667                         t = mono_type_get_underlying_type (t);
2668
2669                         if (!t->byref && t->type == MONO_TYPE_R4) {
2670                                 MonoInst *iargs [1];
2671                                 MonoInst *conv;
2672
2673                                 iargs [0] = in;
2674                                 conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
2675
2676                                 /* The result will be in an int vreg */
2677                                 call->args [i] = conv;
2678                         }
2679                 }
2680         }
2681 #endif
2682
2683         call->need_unbox_trampoline = unbox_trampoline;
2684
2685 #ifdef ENABLE_LLVM
2686         if (COMPILE_LLVM (cfg))
2687                 mono_llvm_emit_call (cfg, call);
2688         else
2689                 mono_arch_emit_call (cfg, call);
2690 #else
2691         mono_arch_emit_call (cfg, call);
2692 #endif
2693
2694         cfg->param_area = MAX (cfg->param_area, call->stack_usage);
2695         cfg->flags |= MONO_CFG_HAS_CALLS;
2696         
2697         return call;
2698 }
2699
2700 static void
2701 set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rgctx_arg)
2702 {
2703         mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
2704         cfg->uses_rgctx_reg = TRUE;
2705         call->rgctx_reg = TRUE;
2706 #ifdef ENABLE_LLVM
2707         call->rgctx_arg_reg = rgctx_reg;
2708 #endif
2709 }       
2710
2711 inline static MonoInst*
2712 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg)
2713 {
2714         MonoCallInst *call;
2715         MonoInst *ins;
2716         int rgctx_reg = -1;
2717         gboolean check_sp = FALSE;
2718
2719         if (cfg->check_pinvoke_callconv && cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
2720                 WrapperInfo *info = mono_marshal_get_wrapper_info (cfg->method);
2721
2722                 if (info && info->subtype == WRAPPER_SUBTYPE_PINVOKE)
2723                         check_sp = TRUE;
2724         }
2725
2726         if (rgctx_arg) {
2727                 rgctx_reg = mono_alloc_preg (cfg);
2728                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2729         }
2730
2731         if (check_sp) {
2732                 if (!cfg->stack_inbalance_var)
2733                         cfg->stack_inbalance_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2734
2735                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2736                 ins->dreg = cfg->stack_inbalance_var->dreg;
2737                 MONO_ADD_INS (cfg->cbb, ins);
2738         }
2739
2740         call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE);
2741
2742         call->inst.sreg1 = addr->dreg;
2743
2744         if (imt_arg)
2745                 emit_imt_argument (cfg, call, NULL, imt_arg);
2746
2747         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2748
2749         if (check_sp) {
2750                 int sp_reg;
2751
2752                 sp_reg = mono_alloc_preg (cfg);
2753
2754                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2755                 ins->dreg = sp_reg;
2756                 MONO_ADD_INS (cfg->cbb, ins);
2757
2758                 /* Restore the stack so we don't crash when throwing the exception */
2759                 MONO_INST_NEW (cfg, ins, OP_SET_SP);
2760                 ins->sreg1 = cfg->stack_inbalance_var->dreg;
2761                 MONO_ADD_INS (cfg->cbb, ins);
2762
2763                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, cfg->stack_inbalance_var->dreg, sp_reg);
2764                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ExecutionEngineException");
2765         }
2766
2767         if (rgctx_arg)
2768                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2769
2770         return (MonoInst*)call;
2771 }
2772
2773 static MonoInst*
2774 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2775
2776 static MonoInst*
2777 emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type);
2778 static MonoInst*
2779 emit_get_rgctx_klass (MonoCompile *cfg, int context_used, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2780
2781 static MonoInst*
2782 mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig, gboolean tail,
2783                                                         MonoInst **args, MonoInst *this_ins, MonoInst *imt_arg, MonoInst *rgctx_arg)
2784 {
2785 #ifndef DISABLE_REMOTING
2786         gboolean might_be_remote = FALSE;
2787 #endif
2788         gboolean virtual_ = this_ins != NULL;
2789         gboolean enable_for_aot = TRUE;
2790         int context_used;
2791         MonoCallInst *call;
2792         MonoInst *call_target = NULL;
2793         int rgctx_reg = 0;
2794         gboolean need_unbox_trampoline;
2795
2796         if (!sig)
2797                 sig = mono_method_signature (method);
2798
2799         if (cfg->llvm_only && (mono_class_is_interface (method->klass)))
2800                 g_assert_not_reached ();
2801
2802         if (rgctx_arg) {
2803                 rgctx_reg = mono_alloc_preg (cfg);
2804                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2805         }
2806
2807         if (method->string_ctor) {
2808                 /* Create the real signature */
2809                 /* FIXME: Cache these */
2810                 MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_mempool (cfg->mempool, sig);
2811                 ctor_sig->ret = &mono_defaults.string_class->byval_arg;
2812
2813                 sig = ctor_sig;
2814         }
2815
2816         context_used = mini_method_check_context_used (cfg, method);
2817
2818 #ifndef DISABLE_REMOTING
2819         might_be_remote = this_ins && sig->hasthis &&
2820                 (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) &&
2821                 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && (!MONO_CHECK_THIS (this_ins) || context_used);
2822
2823         if (might_be_remote && context_used) {
2824                 MonoInst *addr;
2825
2826                 g_assert (cfg->gshared);
2827
2828                 addr = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK);
2829
2830                 return mono_emit_calli (cfg, sig, args, addr, NULL, NULL);
2831         }
2832 #endif
2833
2834         if (cfg->llvm_only && !call_target && virtual_ && (method->flags & METHOD_ATTRIBUTE_VIRTUAL))
2835                 return emit_llvmonly_virtual_call (cfg, method, sig, 0, args);
2836
2837         need_unbox_trampoline = method->klass == mono_defaults.object_class || mono_class_is_interface (method->klass);
2838
2839         call = mono_emit_call_args (cfg, sig, args, FALSE, virtual_, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline);
2840
2841 #ifndef DISABLE_REMOTING
2842         if (might_be_remote)
2843                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2844         else
2845 #endif
2846                 call->method = method;
2847         call->inst.flags |= MONO_INST_HAS_METHOD;
2848         call->inst.inst_left = this_ins;
2849         call->tail_call = tail;
2850
2851         if (virtual_) {
2852                 int vtable_reg, slot_reg, this_reg;
2853                 int offset;
2854
2855                 this_reg = this_ins->dreg;
2856
2857                 if (!cfg->llvm_only && (method->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (method->name, "Invoke")) {
2858                         MonoInst *dummy_use;
2859
2860                         MONO_EMIT_NULL_CHECK (cfg, this_reg);
2861
2862                         /* Make a call to delegate->invoke_impl */
2863                         call->inst.inst_basereg = this_reg;
2864                         call->inst.inst_offset = MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl);
2865                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2866
2867                         /* We must emit a dummy use here because the delegate trampoline will
2868                         replace the 'this' argument with the delegate target making this activation
2869                         no longer a root for the delegate.
2870                         This is an issue for delegates that target collectible code such as dynamic
2871                         methods of GC'able assemblies.
2872
2873                         For a test case look into #667921.
2874
2875                         FIXME: a dummy use is not the best way to do it as the local register allocator
2876                         will put it on a caller save register and spil it around the call. 
2877                         Ideally, we would either put it on a callee save register or only do the store part.  
2878                          */
2879                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [0]);
2880
2881                         return (MonoInst*)call;
2882                 }
2883
2884                 if ((!cfg->compile_aot || enable_for_aot) && 
2885                         (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
2886                          (MONO_METHOD_IS_FINAL (method) &&
2887                           method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)) &&
2888                         !(mono_class_is_marshalbyref (method->klass) && context_used)) {
2889                         /* 
2890                          * the method is not virtual, we just need to ensure this is not null
2891                          * and then we can call the method directly.
2892                          */
2893 #ifndef DISABLE_REMOTING
2894                         if (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) {
2895                                 /* 
2896                                  * The check above ensures method is not gshared, this is needed since
2897                                  * gshared methods can't have wrappers.
2898                                  */
2899                                 method = call->method = mono_marshal_get_remoting_invoke_with_check (method);
2900                         }
2901 #endif
2902
2903                         if (!method->string_ctor)
2904                                 MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2905
2906                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2907                 } else if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && MONO_METHOD_IS_FINAL (method)) {
2908                         /*
2909                          * the method is virtual, but we can statically dispatch since either
2910                          * it's class or the method itself are sealed.
2911                          * But first we need to ensure it's not a null reference.
2912                          */
2913                         MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2914
2915                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2916                 } else if (call_target) {
2917                         vtable_reg = alloc_preg (cfg);
2918                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2919
2920                         call->inst.opcode = callvirt_to_call_reg (call->inst.opcode);
2921                         call->inst.sreg1 = call_target->dreg;
2922                         call->inst.flags &= !MONO_INST_HAS_METHOD;
2923                 } else {
2924                         vtable_reg = alloc_preg (cfg);
2925                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2926                         if (mono_class_is_interface (method->klass)) {
2927                                 guint32 imt_slot = mono_method_get_imt_slot (method);
2928                                 emit_imt_argument (cfg, call, call->method, imt_arg);
2929                                 slot_reg = vtable_reg;
2930                                 offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
2931                         } else {
2932                                 slot_reg = vtable_reg;
2933                                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) +
2934                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
2935                                 if (imt_arg) {
2936                                         g_assert (mono_method_signature (method)->generic_param_count);
2937                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2938                                 }
2939                         }
2940
2941                         call->inst.sreg1 = slot_reg;
2942                         call->inst.inst_offset = offset;
2943                         call->is_virtual = TRUE;
2944                 }
2945         }
2946
2947         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2948
2949         if (rgctx_arg)
2950                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2951
2952         return (MonoInst*)call;
2953 }
2954
2955 MonoInst*
2956 mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this_ins)
2957 {
2958         return mono_emit_method_call_full (cfg, method, mono_method_signature (method), FALSE, args, this_ins, NULL, NULL);
2959 }
2960
2961 MonoInst*
2962 mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig,
2963                                            MonoInst **args)
2964 {
2965         MonoCallInst *call;
2966
2967         g_assert (sig);
2968
2969         call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE, FALSE, FALSE);
2970         call->fptr = func;
2971
2972         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2973
2974         return (MonoInst*)call;
2975 }
2976
2977 MonoInst*
2978 mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args)
2979 {
2980         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2981
2982         g_assert (info);
2983
2984         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2985 }
2986
2987 /*
2988  * mono_emit_abs_call:
2989  *
2990  *   Emit a call to the runtime function described by PATCH_TYPE and DATA.
2991  */
2992 inline static MonoInst*
2993 mono_emit_abs_call (MonoCompile *cfg, MonoJumpInfoType patch_type, gconstpointer data, 
2994                                         MonoMethodSignature *sig, MonoInst **args)
2995 {
2996         MonoJumpInfo *ji = mono_patch_info_new (cfg->mempool, 0, patch_type, data);
2997         MonoInst *ins;
2998
2999         /* 
3000          * We pass ji as the call address, the PATCH_INFO_ABS resolving code will
3001          * handle it.
3002          */
3003         if (cfg->abs_patches == NULL)
3004                 cfg->abs_patches = g_hash_table_new (NULL, NULL);
3005         g_hash_table_insert (cfg->abs_patches, ji, ji);
3006         ins = mono_emit_native_call (cfg, ji, sig, args);
3007         ((MonoCallInst*)ins)->fptr_is_patch = TRUE;
3008         return ins;
3009 }
3010
3011 static MonoMethodSignature*
3012 sig_to_rgctx_sig (MonoMethodSignature *sig)
3013 {
3014         // FIXME: memory allocation
3015         MonoMethodSignature *res;
3016         int i;
3017
3018         res = (MonoMethodSignature *)g_malloc (MONO_SIZEOF_METHOD_SIGNATURE + (sig->param_count + 1) * sizeof (MonoType*));
3019         memcpy (res, sig, MONO_SIZEOF_METHOD_SIGNATURE);
3020         res->param_count = sig->param_count + 1;
3021         for (i = 0; i < sig->param_count; ++i)
3022                 res->params [i] = sig->params [i];
3023         res->params [sig->param_count] = &mono_defaults.int_class->this_arg;
3024         return res;
3025 }
3026
3027 /* Make an indirect call to FSIG passing an additional argument */
3028 static MonoInst*
3029 emit_extra_arg_calli (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **orig_args, int arg_reg, MonoInst *call_target)
3030 {
3031         MonoMethodSignature *csig;
3032         MonoInst *args_buf [16];
3033         MonoInst **args;
3034         int i, pindex, tmp_reg;
3035
3036         /* Make a call with an rgctx/extra arg */
3037         if (fsig->param_count + 2 < 16)
3038                 args = args_buf;
3039         else
3040                 args = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (fsig->param_count + 2));
3041         pindex = 0;
3042         if (fsig->hasthis)
3043                 args [pindex ++] = orig_args [0];
3044         for (i = 0; i < fsig->param_count; ++i)
3045                 args [pindex ++] = orig_args [fsig->hasthis + i];
3046         tmp_reg = alloc_preg (cfg);
3047         EMIT_NEW_UNALU (cfg, args [pindex], OP_MOVE, tmp_reg, arg_reg);
3048         csig = sig_to_rgctx_sig (fsig);
3049         return mono_emit_calli (cfg, csig, args, call_target, NULL, NULL);
3050 }
3051
3052 /* Emit an indirect call to the function descriptor ADDR */
3053 static MonoInst*
3054 emit_llvmonly_calli (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, MonoInst *addr)
3055 {
3056         int addr_reg, arg_reg;
3057         MonoInst *call_target;
3058
3059         g_assert (cfg->llvm_only);
3060
3061         /*
3062          * addr points to a <addr, arg> pair, load both of them, and
3063          * make a call to addr, passing arg as an extra arg.
3064          */
3065         addr_reg = alloc_preg (cfg);
3066         EMIT_NEW_LOAD_MEMBASE (cfg, call_target, OP_LOAD_MEMBASE, addr_reg, addr->dreg, 0);
3067         arg_reg = alloc_preg (cfg);
3068         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, arg_reg, addr->dreg, sizeof (gpointer));
3069
3070         return emit_extra_arg_calli (cfg, fsig, args, arg_reg, call_target);
3071 }
3072
3073 static gboolean
3074 direct_icalls_enabled (MonoCompile *cfg)
3075 {
3076         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
3077 #ifdef TARGET_AMD64
3078         if (cfg->compile_llvm && !cfg->llvm_only)
3079                 return FALSE;
3080 #endif
3081         if (cfg->gen_sdb_seq_points || cfg->disable_direct_icalls)
3082                 return FALSE;
3083         return TRUE;
3084 }
3085
3086 MonoInst*
3087 mono_emit_jit_icall_by_info (MonoCompile *cfg, int il_offset, MonoJitICallInfo *info, MonoInst **args)
3088 {
3089         /*
3090          * Call the jit icall without a wrapper if possible.
3091          * The wrapper is needed for the following reasons:
3092          * - to handle exceptions thrown using mono_raise_exceptions () from the
3093          *   icall function. The EH code needs the lmf frame pushed by the
3094          *   wrapper to be able to unwind back to managed code.
3095          * - to be able to do stack walks for asynchronously suspended
3096          *   threads when debugging.
3097          */
3098         if (info->no_raise && direct_icalls_enabled (cfg)) {
3099                 char *name;
3100                 int costs;
3101
3102                 if (!info->wrapper_method) {
3103                         name = g_strdup_printf ("__icall_wrapper_%s", info->name);
3104                         info->wrapper_method = mono_marshal_get_icall_wrapper (info->sig, name, info->func, TRUE);
3105                         g_free (name);
3106                         mono_memory_barrier ();
3107                 }
3108
3109                 /*
3110                  * Inline the wrapper method, which is basically a call to the C icall, and
3111                  * an exception check.
3112                  */
3113                 costs = inline_method (cfg, info->wrapper_method, NULL,
3114                                                            args, NULL, il_offset, TRUE);
3115                 g_assert (costs > 0);
3116                 g_assert (!MONO_TYPE_IS_VOID (info->sig->ret));
3117
3118                 return args [0];
3119         } else {
3120                 return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
3121         }
3122 }
3123  
3124 static MonoInst*
3125 mono_emit_widen_call_res (MonoCompile *cfg, MonoInst *ins, MonoMethodSignature *fsig)
3126 {
3127         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
3128                 if ((fsig->pinvoke || LLVM_ENABLED) && !fsig->ret->byref) {
3129                         int widen_op = -1;
3130
3131                         /* 
3132                          * Native code might return non register sized integers 
3133                          * without initializing the upper bits.
3134                          */
3135                         switch (mono_type_to_load_membase (cfg, fsig->ret)) {
3136                         case OP_LOADI1_MEMBASE:
3137                                 widen_op = OP_ICONV_TO_I1;
3138                                 break;
3139                         case OP_LOADU1_MEMBASE:
3140                                 widen_op = OP_ICONV_TO_U1;
3141                                 break;
3142                         case OP_LOADI2_MEMBASE:
3143                                 widen_op = OP_ICONV_TO_I2;
3144                                 break;
3145                         case OP_LOADU2_MEMBASE:
3146                                 widen_op = OP_ICONV_TO_U2;
3147                                 break;
3148                         default:
3149                                 break;
3150                         }
3151
3152                         if (widen_op != -1) {
3153                                 int dreg = alloc_preg (cfg);
3154                                 MonoInst *widen;
3155
3156                                 EMIT_NEW_UNALU (cfg, widen, widen_op, dreg, ins->dreg);
3157                                 widen->type = ins->type;
3158                                 ins = widen;
3159                         }
3160                 }
3161         }
3162
3163         return ins;
3164 }
3165
3166
3167 static void
3168 emit_method_access_failure (MonoCompile *cfg, MonoMethod *method, MonoMethod *cil_method)
3169 {
3170         MonoInst *args [16];
3171
3172         args [0] = emit_get_rgctx_method (cfg, mono_method_check_context_used (method), method, MONO_RGCTX_INFO_METHOD);
3173         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cil_method), cil_method, MONO_RGCTX_INFO_METHOD);
3174
3175         mono_emit_jit_icall (cfg, mono_throw_method_access, args);
3176 }
3177
3178 static MonoMethod*
3179 get_memcpy_method (void)
3180 {
3181         static MonoMethod *memcpy_method = NULL;
3182         if (!memcpy_method) {
3183                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
3184                 if (!memcpy_method)
3185                         g_error ("Old corlib found. Install a new one");
3186         }
3187         return memcpy_method;
3188 }
3189
3190 static void
3191 create_write_barrier_bitmap (MonoCompile *cfg, MonoClass *klass, unsigned *wb_bitmap, int offset)
3192 {
3193         MonoClassField *field;
3194         gpointer iter = NULL;
3195
3196         while ((field = mono_class_get_fields (klass, &iter))) {
3197                 int foffset;
3198
3199                 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3200                         continue;
3201                 foffset = klass->valuetype ? field->offset - sizeof (MonoObject): field->offset;
3202                 if (mini_type_is_reference (mono_field_get_type (field))) {
3203                         g_assert ((foffset % SIZEOF_VOID_P) == 0);
3204                         *wb_bitmap |= 1 << ((offset + foffset) / SIZEOF_VOID_P);
3205                 } else {
3206                         MonoClass *field_class = mono_class_from_mono_type (field->type);
3207                         if (field_class->has_references)
3208                                 create_write_barrier_bitmap (cfg, field_class, wb_bitmap, offset + foffset);
3209                 }
3210         }
3211 }
3212
3213 static void
3214 emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value)
3215 {
3216         int card_table_shift_bits;
3217         gpointer card_table_mask;
3218         guint8 *card_table;
3219         MonoInst *dummy_use;
3220         int nursery_shift_bits;
3221         size_t nursery_size;
3222
3223         if (!cfg->gen_write_barriers)
3224                 return;
3225
3226         card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
3227
3228         mono_gc_get_nursery (&nursery_shift_bits, &nursery_size);
3229
3230         if (cfg->backend->have_card_table_wb && !cfg->compile_aot && card_table && nursery_shift_bits > 0 && !COMPILE_LLVM (cfg)) {
3231                 MonoInst *wbarrier;
3232
3233                 MONO_INST_NEW (cfg, wbarrier, OP_CARD_TABLE_WBARRIER);
3234                 wbarrier->sreg1 = ptr->dreg;
3235                 wbarrier->sreg2 = value->dreg;
3236                 MONO_ADD_INS (cfg->cbb, wbarrier);
3237         } else if (card_table && !cfg->compile_aot && !mono_gc_card_table_nursery_check ()) {
3238                 int offset_reg = alloc_preg (cfg);
3239                 int card_reg;
3240                 MonoInst *ins;
3241
3242                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, offset_reg, ptr->dreg, card_table_shift_bits);
3243                 if (card_table_mask)
3244                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, offset_reg, offset_reg, card_table_mask);
3245
3246                 /*We can't use PADD_IMM since the cardtable might end up in high addresses and amd64 doesn't support
3247                  * IMM's larger than 32bits.
3248                  */
3249                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
3250                 card_reg = ins->dreg;
3251
3252                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, offset_reg, offset_reg, card_reg);
3253                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, offset_reg, 0, 1);
3254         } else {
3255                 MonoMethod *write_barrier = mono_gc_get_write_barrier ();
3256                 mono_emit_method_call (cfg, write_barrier, &ptr, NULL);
3257         }
3258
3259         EMIT_NEW_DUMMY_USE (cfg, dummy_use, value);
3260 }
3261
3262 static gboolean
3263 mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align)
3264 {
3265         int dest_ptr_reg, tmp_reg, destreg, srcreg, offset;
3266         unsigned need_wb = 0;
3267
3268         if (align == 0)
3269                 align = 4;
3270
3271         /*types with references can't have alignment smaller than sizeof(void*) */
3272         if (align < SIZEOF_VOID_P)
3273                 return FALSE;
3274
3275         /*This value cannot be bigger than 32 due to the way we calculate the required wb bitmap.*/
3276         if (size > 32 * SIZEOF_VOID_P)
3277                 return FALSE;
3278
3279         create_write_barrier_bitmap (cfg, klass, &need_wb, 0);
3280
3281         /* We don't unroll more than 5 stores to avoid code bloat. */
3282         if (size > 5 * SIZEOF_VOID_P) {
3283                 /*This is harmless and simplify mono_gc_wbarrier_value_copy_bitmap */
3284                 size += (SIZEOF_VOID_P - 1);
3285                 size &= ~(SIZEOF_VOID_P - 1);
3286
3287                 EMIT_NEW_ICONST (cfg, iargs [2], size);
3288                 EMIT_NEW_ICONST (cfg, iargs [3], need_wb);
3289                 mono_emit_jit_icall (cfg, mono_gc_wbarrier_value_copy_bitmap, iargs);
3290                 return TRUE;
3291         }
3292
3293         destreg = iargs [0]->dreg;
3294         srcreg = iargs [1]->dreg;
3295         offset = 0;
3296
3297         dest_ptr_reg = alloc_preg (cfg);
3298         tmp_reg = alloc_preg (cfg);
3299
3300         /*tmp = dreg*/
3301         EMIT_NEW_UNALU (cfg, iargs [0], OP_MOVE, dest_ptr_reg, destreg);
3302
3303         while (size >= SIZEOF_VOID_P) {
3304                 MonoInst *load_inst;
3305                 MONO_INST_NEW (cfg, load_inst, OP_LOAD_MEMBASE);
3306                 load_inst->dreg = tmp_reg;
3307                 load_inst->inst_basereg = srcreg;
3308                 load_inst->inst_offset = offset;
3309                 MONO_ADD_INS (cfg->cbb, load_inst);
3310
3311                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg);
3312
3313                 if (need_wb & 0x1)
3314                         emit_write_barrier (cfg, iargs [0], load_inst);
3315
3316                 offset += SIZEOF_VOID_P;
3317                 size -= SIZEOF_VOID_P;
3318                 need_wb >>= 1;
3319
3320                 /*tmp += sizeof (void*)*/
3321                 if (size >= SIZEOF_VOID_P) {
3322                         NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dest_ptr_reg, dest_ptr_reg, SIZEOF_VOID_P);
3323                         MONO_ADD_INS (cfg->cbb, iargs [0]);
3324                 }
3325         }
3326
3327         /* Those cannot be references since size < sizeof (void*) */
3328         while (size >= 4) {
3329                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tmp_reg, srcreg, offset);
3330                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, tmp_reg);
3331                 offset += 4;
3332                 size -= 4;
3333         }
3334
3335         while (size >= 2) {
3336                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmp_reg, srcreg, offset);
3337                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, tmp_reg);
3338                 offset += 2;
3339                 size -= 2;
3340         }
3341
3342         while (size >= 1) {
3343                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmp_reg, srcreg, offset);
3344                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, tmp_reg);
3345                 offset += 1;
3346                 size -= 1;
3347         }
3348
3349         return TRUE;
3350 }
3351
3352 /*
3353  * Emit code to copy a valuetype of type @klass whose address is stored in
3354  * @src->dreg to memory whose address is stored at @dest->dreg.
3355  */
3356 void
3357 mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native)
3358 {
3359         MonoInst *iargs [4];
3360         int n;
3361         guint32 align = 0;
3362         MonoMethod *memcpy_method;
3363         MonoInst *size_ins = NULL;
3364         MonoInst *memcpy_ins = NULL;
3365
3366         g_assert (klass);
3367         if (cfg->gshared)
3368                 klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
3369
3370         /*
3371          * This check breaks with spilled vars... need to handle it during verification anyway.
3372          * g_assert (klass && klass == src->klass && klass == dest->klass);
3373          */
3374
3375         if (mini_is_gsharedvt_klass (klass)) {
3376                 g_assert (!native);
3377                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3378                 memcpy_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_MEMCPY);
3379         }
3380
3381         if (native)
3382                 n = mono_class_native_size (klass, &align);
3383         else
3384                 n = mono_class_value_size (klass, &align);
3385
3386         /* if native is true there should be no references in the struct */
3387         if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) {
3388                 /* Avoid barriers when storing to the stack */
3389                 if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
3390                           (dest->opcode == OP_LDADDR))) {
3391                         int context_used;
3392
3393                         iargs [0] = dest;
3394                         iargs [1] = src;
3395
3396                         context_used = mini_class_check_context_used (cfg, klass);
3397
3398                         /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
3399                         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
3400                                 return;
3401                         } else if (context_used) {
3402                                 iargs [2] = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3403                         }  else {
3404                                 iargs [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
3405                                 if (!cfg->compile_aot)
3406                                         mono_class_compute_gc_descriptor (klass);
3407                         }
3408
3409                         if (size_ins)
3410                                 mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
3411                         else
3412                                 mono_emit_jit_icall (cfg, mono_value_copy, iargs);
3413                         return;
3414                 }
3415         }
3416
3417         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 8) {
3418                 /* FIXME: Optimize the case when src/dest is OP_LDADDR */
3419                 mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, n, align);
3420         } else {
3421                 iargs [0] = dest;
3422                 iargs [1] = src;
3423                 if (size_ins)
3424                         iargs [2] = size_ins;
3425                 else
3426                         EMIT_NEW_ICONST (cfg, iargs [2], n);
3427                 
3428                 memcpy_method = get_memcpy_method ();
3429                 if (memcpy_ins)
3430                         mono_emit_calli (cfg, mono_method_signature (memcpy_method), iargs, memcpy_ins, NULL, NULL);
3431                 else
3432                         mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
3433         }
3434 }
3435
3436 static MonoMethod*
3437 get_memset_method (void)
3438 {
3439         static MonoMethod *memset_method = NULL;
3440         if (!memset_method) {
3441                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
3442                 if (!memset_method)
3443                         g_error ("Old corlib found. Install a new one");
3444         }
3445         return memset_method;
3446 }
3447
3448 void
3449 mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass)
3450 {
3451         MonoInst *iargs [3];
3452         int n;
3453         guint32 align;
3454         MonoMethod *memset_method;
3455         MonoInst *size_ins = NULL;
3456         MonoInst *bzero_ins = NULL;
3457         static MonoMethod *bzero_method;
3458
3459         /* FIXME: Optimize this for the case when dest is an LDADDR */
3460         mono_class_init (klass);
3461         if (mini_is_gsharedvt_klass (klass)) {
3462                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3463                 bzero_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_BZERO);
3464                 if (!bzero_method)
3465                         bzero_method = mono_class_get_method_from_name (mono_defaults.string_class, "bzero_aligned_1", 2);
3466                 g_assert (bzero_method);
3467                 iargs [0] = dest;
3468                 iargs [1] = size_ins;
3469                 mono_emit_calli (cfg, mono_method_signature (bzero_method), iargs, bzero_ins, NULL, NULL);
3470                 return;
3471         }
3472
3473         klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
3474
3475         n = mono_class_value_size (klass, &align);
3476
3477         if (n <= sizeof (gpointer) * 8) {
3478                 mini_emit_memset (cfg, dest->dreg, 0, n, 0, align);
3479         }
3480         else {
3481                 memset_method = get_memset_method ();
3482                 iargs [0] = dest;
3483                 EMIT_NEW_ICONST (cfg, iargs [1], 0);
3484                 EMIT_NEW_ICONST (cfg, iargs [2], n);
3485                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
3486         }
3487 }
3488
3489 /*
3490  * emit_get_rgctx:
3491  *
3492  *   Emit IR to return either the this pointer for instance method,
3493  * or the mrgctx for static methods.
3494  */
3495 static MonoInst*
3496 emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used)
3497 {
3498         MonoInst *this_ins = NULL;
3499
3500         g_assert (cfg->gshared);
3501
3502         if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&
3503                         !(context_used & MONO_GENERIC_CONTEXT_USED_METHOD) &&
3504                         !method->klass->valuetype)
3505                 EMIT_NEW_ARGLOAD (cfg, this_ins, 0);
3506
3507         if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
3508                 MonoInst *mrgctx_loc, *mrgctx_var;
3509
3510                 g_assert (!this_ins);
3511                 g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
3512
3513                 mrgctx_loc = mono_get_vtable_var (cfg);
3514                 EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
3515
3516                 return mrgctx_var;
3517         } else if (method->flags & METHOD_ATTRIBUTE_STATIC || method->klass->valuetype) {
3518                 MonoInst *vtable_loc, *vtable_var;
3519
3520                 g_assert (!this_ins);
3521
3522                 vtable_loc = mono_get_vtable_var (cfg);
3523                 EMIT_NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
3524
3525                 if (method->is_inflated && mono_method_get_context (method)->method_inst) {
3526                         MonoInst *mrgctx_var = vtable_var;
3527                         int vtable_reg;
3528
3529                         vtable_reg = alloc_preg (cfg);
3530                         EMIT_NEW_LOAD_MEMBASE (cfg, vtable_var, OP_LOAD_MEMBASE, vtable_reg, mrgctx_var->dreg, MONO_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable));
3531                         vtable_var->type = STACK_PTR;
3532                 }
3533
3534                 return vtable_var;
3535         } else {
3536                 MonoInst *ins;
3537                 int vtable_reg;
3538         
3539                 vtable_reg = alloc_preg (cfg);
3540                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, vtable_reg, this_ins->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3541                 return ins;
3542         }
3543 }
3544
3545 static MonoJumpInfoRgctxEntry *
3546 mono_patch_info_rgctx_entry_new (MonoMemPool *mp, MonoMethod *method, gboolean in_mrgctx, MonoJumpInfoType patch_type, gconstpointer patch_data, MonoRgctxInfoType info_type)
3547 {
3548         MonoJumpInfoRgctxEntry *res = (MonoJumpInfoRgctxEntry *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoRgctxEntry));
3549         res->method = method;
3550         res->in_mrgctx = in_mrgctx;
3551         res->data = (MonoJumpInfo *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
3552         res->data->type = patch_type;
3553         res->data->data.target = patch_data;
3554         res->info_type = info_type;
3555
3556         return res;
3557 }
3558
3559 static inline MonoInst*
3560 emit_rgctx_fetch_inline (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3561 {
3562         MonoInst *args [16];
3563         MonoInst *call;
3564
3565         // FIXME: No fastpath since the slot is not a compile time constant
3566         args [0] = rgctx;
3567         EMIT_NEW_AOTCONST (cfg, args [1], MONO_PATCH_INFO_RGCTX_SLOT_INDEX, entry);
3568         if (entry->in_mrgctx)
3569                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3570         else
3571                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3572         return call;
3573 #if 0
3574         /*
3575          * FIXME: This can be called during decompose, which is a problem since it creates
3576          * new bblocks.
3577          * Also, the fastpath doesn't work since the slot number is dynamically allocated.
3578          */
3579         int i, slot, depth, index, rgctx_reg, val_reg, res_reg;
3580         gboolean mrgctx;
3581         MonoBasicBlock *is_null_bb, *end_bb;
3582         MonoInst *res, *ins, *call;
3583         MonoInst *args[16];
3584
3585         slot = mini_get_rgctx_entry_slot (entry);
3586
3587         mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot);
3588         index = MONO_RGCTX_SLOT_INDEX (slot);
3589         if (mrgctx)
3590                 index += MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
3591         for (depth = 0; ; ++depth) {
3592                 int size = mono_class_rgctx_get_array_size (depth, mrgctx);
3593
3594                 if (index < size - 1)
3595                         break;
3596                 index -= size - 1;
3597         }
3598
3599         NEW_BBLOCK (cfg, end_bb);
3600         NEW_BBLOCK (cfg, is_null_bb);
3601
3602         if (mrgctx) {
3603                 rgctx_reg = rgctx->dreg;
3604         } else {
3605                 rgctx_reg = alloc_preg (cfg);
3606
3607                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, rgctx_reg, rgctx->dreg, MONO_STRUCT_OFFSET (MonoVTable, runtime_generic_context));
3608                 // FIXME: Avoid this check by allocating the table when the vtable is created etc.
3609                 NEW_BBLOCK (cfg, is_null_bb);
3610
3611                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3612                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3613         }
3614
3615         for (i = 0; i < depth; ++i) {
3616                 int array_reg = alloc_preg (cfg);
3617
3618                 /* load ptr to next array */
3619                 if (mrgctx && i == 0)
3620                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT);
3621                 else
3622                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, 0);
3623                 rgctx_reg = array_reg;
3624                 /* is the ptr null? */
3625                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3626                 /* if yes, jump to actual trampoline */
3627                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3628         }
3629
3630         /* fetch slot */
3631         val_reg = alloc_preg (cfg);
3632         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, val_reg, rgctx_reg, (index + 1) * sizeof (gpointer));
3633         /* is the slot null? */
3634         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, val_reg, 0);
3635         /* if yes, jump to actual trampoline */
3636         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3637
3638         /* Fastpath */
3639         res_reg = alloc_preg (cfg);
3640         MONO_INST_NEW (cfg, ins, OP_MOVE);
3641         ins->dreg = res_reg;
3642         ins->sreg1 = val_reg;
3643         MONO_ADD_INS (cfg->cbb, ins);
3644         res = ins;
3645         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3646
3647         /* Slowpath */
3648         MONO_START_BB (cfg, is_null_bb);
3649         args [0] = rgctx;
3650         EMIT_NEW_ICONST (cfg, args [1], index);
3651         if (mrgctx)
3652                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3653         else
3654                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3655         MONO_INST_NEW (cfg, ins, OP_MOVE);
3656         ins->dreg = res_reg;
3657         ins->sreg1 = call->dreg;
3658         MONO_ADD_INS (cfg->cbb, ins);
3659         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3660
3661         MONO_START_BB (cfg, end_bb);
3662
3663         return res;
3664 #endif
3665 }
3666
3667 /*
3668  * emit_rgctx_fetch:
3669  *
3670  *   Emit IR to load the value of the rgctx entry ENTRY from the rgctx
3671  * given by RGCTX.
3672  */
3673 static inline MonoInst*
3674 emit_rgctx_fetch (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3675 {
3676         if (cfg->llvm_only)
3677                 return emit_rgctx_fetch_inline (cfg, rgctx, entry);
3678         else
3679                 return mono_emit_abs_call (cfg, MONO_PATCH_INFO_RGCTX_FETCH, entry, helper_sig_rgctx_lazy_fetch_trampoline, &rgctx);
3680 }
3681
3682 static MonoInst*
3683 emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
3684                                           MonoClass *klass, MonoRgctxInfoType rgctx_type)
3685 {
3686         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);
3687         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3688
3689         return emit_rgctx_fetch (cfg, rgctx, entry);
3690 }
3691
3692 static MonoInst*
3693 emit_get_rgctx_sig (MonoCompile *cfg, int context_used,
3694                                         MonoMethodSignature *sig, MonoRgctxInfoType rgctx_type)
3695 {
3696         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);
3697         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3698
3699         return emit_rgctx_fetch (cfg, rgctx, entry);
3700 }
3701
3702 static MonoInst*
3703 emit_get_rgctx_gsharedvt_call (MonoCompile *cfg, int context_used,
3704                                                            MonoMethodSignature *sig, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3705 {
3706         MonoJumpInfoGSharedVtCall *call_info;
3707         MonoJumpInfoRgctxEntry *entry;
3708         MonoInst *rgctx;
3709
3710         call_info = (MonoJumpInfoGSharedVtCall *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoGSharedVtCall));
3711         call_info->sig = sig;
3712         call_info->method = cmethod;
3713
3714         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);
3715         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3716
3717         return emit_rgctx_fetch (cfg, rgctx, entry);
3718 }
3719
3720 /*
3721  * emit_get_rgctx_virt_method:
3722  *
3723  *   Return data for method VIRT_METHOD for a receiver of type KLASS.
3724  */
3725 static MonoInst*
3726 emit_get_rgctx_virt_method (MonoCompile *cfg, int context_used,
3727                                                         MonoClass *klass, MonoMethod *virt_method, MonoRgctxInfoType rgctx_type)
3728 {
3729         MonoJumpInfoVirtMethod *info;
3730         MonoJumpInfoRgctxEntry *entry;
3731         MonoInst *rgctx;
3732
3733         info = (MonoJumpInfoVirtMethod *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoVirtMethod));
3734         info->klass = klass;
3735         info->method = virt_method;
3736
3737         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);
3738         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3739
3740         return emit_rgctx_fetch (cfg, rgctx, entry);
3741 }
3742
3743 static MonoInst*
3744 emit_get_rgctx_gsharedvt_method (MonoCompile *cfg, int context_used,
3745                                                                  MonoMethod *cmethod, MonoGSharedVtMethodInfo *info)
3746 {
3747         MonoJumpInfoRgctxEntry *entry;
3748         MonoInst *rgctx;
3749
3750         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);
3751         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3752
3753         return emit_rgctx_fetch (cfg, rgctx, entry);
3754 }
3755
3756 /*
3757  * emit_get_rgctx_method:
3758  *
3759  *   Emit IR to load the property RGCTX_TYPE of CMETHOD. If context_used is 0, emit
3760  * normal constants, else emit a load from the rgctx.
3761  */
3762 static MonoInst*
3763 emit_get_rgctx_method (MonoCompile *cfg, int context_used,
3764                                            MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3765 {
3766         if (!context_used) {
3767                 MonoInst *ins;
3768
3769                 switch (rgctx_type) {
3770                 case MONO_RGCTX_INFO_METHOD:
3771                         EMIT_NEW_METHODCONST (cfg, ins, cmethod);
3772                         return ins;
3773                 case MONO_RGCTX_INFO_METHOD_RGCTX:
3774                         EMIT_NEW_METHOD_RGCTX_CONST (cfg, ins, cmethod);
3775                         return ins;
3776                 default:
3777                         g_assert_not_reached ();
3778                 }
3779         } else {
3780                 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);
3781                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3782
3783                 return emit_rgctx_fetch (cfg, rgctx, entry);
3784         }
3785 }
3786
3787 static MonoInst*
3788 emit_get_rgctx_field (MonoCompile *cfg, int context_used,
3789                                           MonoClassField *field, MonoRgctxInfoType rgctx_type)
3790 {
3791         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);
3792         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3793
3794         return emit_rgctx_fetch (cfg, rgctx, entry);
3795 }
3796
3797 static int
3798 get_gsharedvt_info_slot (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3799 {
3800         MonoGSharedVtMethodInfo *info = cfg->gsharedvt_info;
3801         MonoRuntimeGenericContextInfoTemplate *template_;
3802         int i, idx;
3803
3804         g_assert (info);
3805
3806         for (i = 0; i < info->num_entries; ++i) {
3807                 MonoRuntimeGenericContextInfoTemplate *otemplate = &info->entries [i];
3808
3809                 if (otemplate->info_type == rgctx_type && otemplate->data == data && rgctx_type != MONO_RGCTX_INFO_LOCAL_OFFSET)
3810                         return i;
3811         }
3812
3813         if (info->num_entries == info->count_entries) {
3814                 MonoRuntimeGenericContextInfoTemplate *new_entries;
3815                 int new_count_entries = info->count_entries ? info->count_entries * 2 : 16;
3816
3817                 new_entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * new_count_entries);
3818
3819                 memcpy (new_entries, info->entries, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
3820                 info->entries = new_entries;
3821                 info->count_entries = new_count_entries;
3822         }
3823
3824         idx = info->num_entries;
3825         template_ = &info->entries [idx];
3826         template_->info_type = rgctx_type;
3827         template_->data = data;
3828
3829         info->num_entries ++;
3830
3831         return idx;
3832 }
3833
3834 /*
3835  * emit_get_gsharedvt_info:
3836  *
3837  *   This is similar to emit_get_rgctx_.., but loads the data from the gsharedvt info var instead of calling an rgctx fetch trampoline.
3838  */
3839 static MonoInst*
3840 emit_get_gsharedvt_info (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3841 {
3842         MonoInst *ins;
3843         int idx, dreg;
3844
3845         idx = get_gsharedvt_info_slot (cfg, data, rgctx_type);
3846         /* Load info->entries [idx] */
3847         dreg = alloc_preg (cfg);
3848         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, cfg->gsharedvt_info_var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
3849
3850         return ins;
3851 }
3852
3853 static MonoInst*
3854 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type)
3855 {
3856         return emit_get_gsharedvt_info (cfg, &klass->byval_arg, rgctx_type);
3857 }
3858
3859 /*
3860  * On return the caller must check @klass for load errors.
3861  */
3862 static void
3863 emit_class_init (MonoCompile *cfg, MonoClass *klass)
3864 {
3865         MonoInst *vtable_arg;
3866         int context_used;
3867
3868         context_used = mini_class_check_context_used (cfg, klass);
3869
3870         if (context_used) {
3871                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
3872                                                                                    klass, MONO_RGCTX_INFO_VTABLE);
3873         } else {
3874                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3875
3876                 if (!vtable)
3877                         return;
3878                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
3879         }
3880
3881         if (!COMPILE_LLVM (cfg) && cfg->backend->have_op_generic_class_init) {
3882                 MonoInst *ins;
3883
3884                 /*
3885                  * Using an opcode instead of emitting IR here allows the hiding of the call inside the opcode,
3886                  * so this doesn't have to clobber any regs and it doesn't break basic blocks.
3887                  */
3888                 MONO_INST_NEW (cfg, ins, OP_GENERIC_CLASS_INIT);
3889                 ins->sreg1 = vtable_arg->dreg;
3890                 MONO_ADD_INS (cfg->cbb, ins);
3891         } else {
3892                 static int byte_offset = -1;
3893                 static guint8 bitmask;
3894                 int bits_reg, inited_reg;
3895                 MonoBasicBlock *inited_bb;
3896                 MonoInst *args [16];
3897
3898                 if (byte_offset < 0)
3899                         mono_marshal_find_bitfield_offset (MonoVTable, initialized, &byte_offset, &bitmask);
3900
3901                 bits_reg = alloc_ireg (cfg);
3902                 inited_reg = alloc_ireg (cfg);
3903
3904                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, bits_reg, vtable_arg->dreg, byte_offset);
3905                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, inited_reg, bits_reg, bitmask);
3906
3907                 NEW_BBLOCK (cfg, inited_bb);
3908
3909                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, inited_reg, 0);
3910                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, inited_bb);
3911
3912                 args [0] = vtable_arg;
3913                 mono_emit_jit_icall (cfg, mono_generic_class_init, args);
3914
3915                 MONO_START_BB (cfg, inited_bb);
3916         }
3917 }
3918
3919 static void
3920 emit_seq_point (MonoCompile *cfg, MonoMethod *method, guint8* ip, gboolean intr_loc, gboolean nonempty_stack)
3921 {
3922         MonoInst *ins;
3923
3924         if (cfg->gen_seq_points && cfg->method == method) {
3925                 NEW_SEQ_POINT (cfg, ins, ip - cfg->header->code, intr_loc);
3926                 if (nonempty_stack)
3927                         ins->flags |= MONO_INST_NONEMPTY_STACK;
3928                 MONO_ADD_INS (cfg->cbb, ins);
3929         }
3930 }
3931
3932 static void
3933 save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean null_check)
3934 {
3935         if (mini_get_debug_options ()->better_cast_details) {
3936                 int vtable_reg = alloc_preg (cfg);
3937                 int klass_reg = alloc_preg (cfg);
3938                 MonoBasicBlock *is_null_bb = NULL;
3939                 MonoInst *tls_get;
3940                 int to_klass_reg, context_used;
3941
3942                 if (null_check) {
3943                         NEW_BBLOCK (cfg, is_null_bb);
3944
3945                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3946                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3947                 }
3948
3949                 tls_get = mono_get_jit_tls_intrinsic (cfg);
3950                 if (!tls_get) {
3951                         fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
3952                         exit (1);
3953                 }
3954
3955                 MONO_ADD_INS (cfg->cbb, tls_get);
3956                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3957                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3958
3959                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
3960
3961                 context_used = mini_class_check_context_used (cfg, klass);
3962                 if (context_used) {
3963                         MonoInst *class_ins;
3964
3965                         class_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3966                         to_klass_reg = class_ins->dreg;
3967                 } else {
3968                         to_klass_reg = alloc_preg (cfg);
3969                         MONO_EMIT_NEW_CLASSCONST (cfg, to_klass_reg, klass);
3970                 }
3971                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
3972
3973                 if (null_check)
3974                         MONO_START_BB (cfg, is_null_bb);
3975         }
3976 }
3977
3978 static void
3979 reset_cast_details (MonoCompile *cfg)
3980 {
3981         /* Reset the variables holding the cast details */
3982         if (mini_get_debug_options ()->better_cast_details) {
3983                 MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
3984
3985                 MONO_ADD_INS (cfg->cbb, tls_get);
3986                 /* It is enough to reset the from field */
3987                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
3988         }
3989 }
3990
3991 /*
3992  * On return the caller must check @array_class for load errors
3993  */
3994 static void
3995 mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_class)
3996 {
3997         int vtable_reg = alloc_preg (cfg);
3998         int context_used;
3999
4000         context_used = mini_class_check_context_used (cfg, array_class);
4001
4002         save_cast_details (cfg, array_class, obj->dreg, FALSE);
4003
4004         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4005
4006         if (cfg->opt & MONO_OPT_SHARED) {
4007                 int class_reg = alloc_preg (cfg);
4008                 MonoInst *ins;
4009
4010                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, class_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4011                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, array_class);
4012                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, class_reg, ins->dreg);
4013         } else if (context_used) {
4014                 MonoInst *vtable_ins;
4015
4016                 vtable_ins = emit_get_rgctx_klass (cfg, context_used, array_class, MONO_RGCTX_INFO_VTABLE);
4017                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vtable_ins->dreg);
4018         } else {
4019                 if (cfg->compile_aot) {
4020                         int vt_reg;
4021                         MonoVTable *vtable;
4022
4023                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
4024                                 return;
4025                         vt_reg = alloc_preg (cfg);
4026                         MONO_EMIT_NEW_VTABLECONST (cfg, vt_reg, vtable);
4027                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vt_reg);
4028                 } else {
4029                         MonoVTable *vtable;
4030                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
4031                                 return;
4032                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vtable);
4033                 }
4034         }
4035         
4036         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
4037
4038         reset_cast_details (cfg);
4039 }
4040
4041 /**
4042  * Handles unbox of a Nullable<T>. If context_used is non zero, then shared 
4043  * generic code is generated.
4044  */
4045 static MonoInst*
4046 handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int context_used)
4047 {
4048         MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
4049
4050         if (context_used) {
4051                 MonoInst *rgctx, *addr;
4052
4053                 /* FIXME: What if the class is shared?  We might not
4054                    have to get the address of the method from the
4055                    RGCTX. */
4056                 addr = emit_get_rgctx_method (cfg, context_used, method,
4057                                                                           MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4058                 if (cfg->llvm_only) {
4059                         cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, mono_method_signature (method));
4060                         return emit_llvmonly_calli (cfg, mono_method_signature (method), &val, addr);
4061                 } else {
4062                         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
4063
4064                         return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
4065                 }
4066         } else {
4067                 gboolean pass_vtable, pass_mrgctx;
4068                 MonoInst *rgctx_arg = NULL;
4069
4070                 check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
4071                 g_assert (!pass_mrgctx);
4072
4073                 if (pass_vtable) {
4074                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4075
4076                         g_assert (vtable);
4077                         EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4078                 }
4079
4080                 return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4081         }
4082 }
4083
4084 static MonoInst*
4085 handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_used)
4086 {
4087         MonoInst *add;
4088         int obj_reg;
4089         int vtable_reg = alloc_dreg (cfg ,STACK_PTR);
4090         int klass_reg = alloc_dreg (cfg ,STACK_PTR);
4091         int eclass_reg = alloc_dreg (cfg ,STACK_PTR);
4092         int rank_reg = alloc_dreg (cfg ,STACK_I4);
4093
4094         obj_reg = sp [0]->dreg;
4095         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4096         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
4097
4098         /* FIXME: generics */
4099         g_assert (klass->rank == 0);
4100                         
4101         // Check rank == 0
4102         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 0);
4103         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4104
4105         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4106         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, element_class));
4107
4108         if (context_used) {
4109                 MonoInst *element_class;
4110
4111                 /* This assertion is from the unboxcast insn */
4112                 g_assert (klass->rank == 0);
4113
4114                 element_class = emit_get_rgctx_klass (cfg, context_used,
4115                                 klass, MONO_RGCTX_INFO_ELEMENT_KLASS);
4116
4117                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, eclass_reg, element_class->dreg);
4118                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4119         } else {
4120                 save_cast_details (cfg, klass->element_class, obj_reg, FALSE);
4121                 mini_emit_class_check (cfg, eclass_reg, klass->element_class);
4122                 reset_cast_details (cfg);
4123         }
4124
4125         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), obj_reg, sizeof (MonoObject));
4126         MONO_ADD_INS (cfg->cbb, add);
4127         add->type = STACK_MP;
4128         add->klass = klass;
4129
4130         return add;
4131 }
4132
4133 static MonoInst*
4134 handle_unbox_gsharedvt (MonoCompile *cfg, MonoClass *klass, MonoInst *obj)
4135 {
4136         MonoInst *addr, *klass_inst, *is_ref, *args[16];
4137         MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4138         MonoInst *ins;
4139         int dreg, addr_reg;
4140
4141         klass_inst = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_KLASS);
4142
4143         /* obj */
4144         args [0] = obj;
4145
4146         /* klass */
4147         args [1] = klass_inst;
4148
4149         /* CASTCLASS */
4150         obj = mono_emit_jit_icall (cfg, mono_object_castclass_unbox, args);
4151
4152         NEW_BBLOCK (cfg, is_ref_bb);
4153         NEW_BBLOCK (cfg, is_nullable_bb);
4154         NEW_BBLOCK (cfg, end_bb);
4155         is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4156         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
4157         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4158
4159         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
4160         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4161
4162         /* This will contain either the address of the unboxed vtype, or an address of the temporary where the ref is stored */
4163         addr_reg = alloc_dreg (cfg, STACK_MP);
4164
4165         /* Non-ref case */
4166         /* UNBOX */
4167         NEW_BIALU_IMM (cfg, addr, OP_ADD_IMM, addr_reg, obj->dreg, sizeof (MonoObject));
4168         MONO_ADD_INS (cfg->cbb, addr);
4169
4170         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4171
4172         /* Ref case */
4173         MONO_START_BB (cfg, is_ref_bb);
4174
4175         /* Save the ref to a temporary */
4176         dreg = alloc_ireg (cfg);
4177         EMIT_NEW_VARLOADA_VREG (cfg, addr, dreg, &klass->byval_arg);
4178         addr->dreg = addr_reg;
4179         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, obj->dreg);
4180         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4181
4182         /* Nullable case */
4183         MONO_START_BB (cfg, is_nullable_bb);
4184
4185         {
4186                 MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX);
4187                 MonoInst *unbox_call;
4188                 MonoMethodSignature *unbox_sig;
4189
4190                 unbox_sig = (MonoMethodSignature *)mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4191                 unbox_sig->ret = &klass->byval_arg;
4192                 unbox_sig->param_count = 1;
4193                 unbox_sig->params [0] = &mono_defaults.object_class->byval_arg;
4194
4195                 if (cfg->llvm_only)
4196                         unbox_call = emit_llvmonly_calli (cfg, unbox_sig, &obj, addr);
4197                 else
4198                         unbox_call = mono_emit_calli (cfg, unbox_sig, &obj, addr, NULL, NULL);
4199
4200                 EMIT_NEW_VARLOADA_VREG (cfg, addr, unbox_call->dreg, &klass->byval_arg);
4201                 addr->dreg = addr_reg;
4202         }
4203
4204         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4205
4206         /* End */
4207         MONO_START_BB (cfg, end_bb);
4208
4209         /* LDOBJ */
4210         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr_reg, 0);
4211
4212         return ins;
4213 }
4214
4215 /*
4216  * Returns NULL and set the cfg exception on error.
4217  */
4218 static MonoInst*
4219 handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_used)
4220 {
4221         MonoInst *iargs [2];
4222         void *alloc_ftn;
4223
4224         if (context_used) {
4225                 MonoInst *data;
4226                 MonoRgctxInfoType rgctx_info;
4227                 MonoInst *iargs [2];
4228                 gboolean known_instance_size = !mini_is_gsharedvt_klass (klass);
4229
4230                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (klass, for_box, known_instance_size);
4231
4232                 if (cfg->opt & MONO_OPT_SHARED)
4233                         rgctx_info = MONO_RGCTX_INFO_KLASS;
4234                 else
4235                         rgctx_info = MONO_RGCTX_INFO_VTABLE;
4236                 data = emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
4237
4238                 if (cfg->opt & MONO_OPT_SHARED) {
4239                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4240                         iargs [1] = data;
4241                         alloc_ftn = ves_icall_object_new;
4242                 } else {
4243                         iargs [0] = data;
4244                         alloc_ftn = ves_icall_object_new_specific;
4245                 }
4246
4247                 if (managed_alloc && !(cfg->opt & MONO_OPT_SHARED)) {
4248                         if (known_instance_size) {
4249                                 int size = mono_class_instance_size (klass);
4250                                 if (size < sizeof (MonoObject))
4251                                         g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4252
4253                                 EMIT_NEW_ICONST (cfg, iargs [1], size);
4254                         }
4255                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4256                 }
4257
4258                 return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4259         }
4260
4261         if (cfg->opt & MONO_OPT_SHARED) {
4262                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4263                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
4264
4265                 alloc_ftn = ves_icall_object_new;
4266         } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !mono_class_is_ginst (klass)) {
4267                 /* This happens often in argument checking code, eg. throw new FooException... */
4268                 /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
4269                 EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
4270                 return mono_emit_jit_icall (cfg, mono_helper_newobj_mscorlib, iargs);
4271         } else {
4272                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
4273                 MonoMethod *managed_alloc = NULL;
4274                 gboolean pass_lw;
4275
4276                 if (!vtable) {
4277                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4278                         cfg->exception_ptr = klass;
4279                         return NULL;
4280                 }
4281
4282                 managed_alloc = mono_gc_get_managed_allocator (klass, for_box, TRUE);
4283
4284                 if (managed_alloc) {
4285                         int size = mono_class_instance_size (klass);
4286                         if (size < sizeof (MonoObject))
4287                                 g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4288
4289                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4290                         EMIT_NEW_ICONST (cfg, iargs [1], size);
4291                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4292                 }
4293                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
4294                 if (pass_lw) {
4295                         guint32 lw = vtable->klass->instance_size;
4296                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
4297                         EMIT_NEW_ICONST (cfg, iargs [0], lw);
4298                         EMIT_NEW_VTABLECONST (cfg, iargs [1], vtable);
4299                 }
4300                 else {
4301                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4302                 }
4303         }
4304
4305         return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4306 }
4307         
4308 /*
4309  * Returns NULL and set the cfg exception on error.
4310  */     
4311 static MonoInst*
4312 handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used)
4313 {
4314         MonoInst *alloc, *ins;
4315
4316         if (mono_class_is_nullable (klass)) {
4317                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
4318
4319                 if (context_used) {
4320                         if (cfg->llvm_only && cfg->gsharedvt) {
4321                                 MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4322                                                                                                                 MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4323                                 return emit_llvmonly_calli (cfg, mono_method_signature (method), &val, addr);
4324                         } else {
4325                                 /* FIXME: What if the class is shared?  We might not
4326                                    have to get the method address from the RGCTX. */
4327                                 MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4328                                                                                                                 MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4329                                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
4330
4331                                 return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
4332                         }
4333                 } else {
4334                         gboolean pass_vtable, pass_mrgctx;
4335                         MonoInst *rgctx_arg = NULL;
4336
4337                         check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
4338                         g_assert (!pass_mrgctx);
4339
4340                         if (pass_vtable) {
4341                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4342
4343                                 g_assert (vtable);
4344                                 EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4345                         }
4346
4347                         return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4348                 }
4349         }
4350
4351         if (mini_is_gsharedvt_klass (klass)) {
4352                 MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4353                 MonoInst *res, *is_ref, *src_var, *addr;
4354                 int dreg;
4355
4356                 dreg = alloc_ireg (cfg);
4357
4358                 NEW_BBLOCK (cfg, is_ref_bb);
4359                 NEW_BBLOCK (cfg, is_nullable_bb);
4360                 NEW_BBLOCK (cfg, end_bb);
4361                 is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4362                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
4363                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4364
4365                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
4366                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4367
4368                 /* Non-ref case */
4369                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4370                 if (!alloc)
4371                         return NULL;
4372                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4373                 ins->opcode = OP_STOREV_MEMBASE;
4374
4375                 EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, alloc->dreg);
4376                 res->type = STACK_OBJ;
4377                 res->klass = klass;
4378                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4379                 
4380                 /* Ref case */
4381                 MONO_START_BB (cfg, is_ref_bb);
4382
4383                 /* val is a vtype, so has to load the value manually */
4384                 src_var = get_vreg_to_inst (cfg, val->dreg);
4385                 if (!src_var)
4386                         src_var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, val->dreg);
4387                 EMIT_NEW_VARLOADA (cfg, addr, src_var, src_var->inst_vtype);
4388                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, addr->dreg, 0);
4389                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4390
4391                 /* Nullable case */
4392                 MONO_START_BB (cfg, is_nullable_bb);
4393
4394                 {
4395                         MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass,
4396                                                                                                         MONO_RGCTX_INFO_NULLABLE_CLASS_BOX);
4397                         MonoInst *box_call;
4398                         MonoMethodSignature *box_sig;
4399
4400                         /*
4401                          * klass is Nullable<T>, need to call Nullable<T>.Box () using a gsharedvt signature, but we cannot
4402                          * construct that method at JIT time, so have to do things by hand.
4403                          */
4404                         box_sig = (MonoMethodSignature *)mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4405                         box_sig->ret = &mono_defaults.object_class->byval_arg;
4406                         box_sig->param_count = 1;
4407                         box_sig->params [0] = &klass->byval_arg;
4408
4409                         if (cfg->llvm_only)
4410                                 box_call = emit_llvmonly_calli (cfg, box_sig, &val, addr);
4411                         else
4412                                 box_call = mono_emit_calli (cfg, box_sig, &val, addr, NULL, NULL);
4413                         EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, box_call->dreg);
4414                         res->type = STACK_OBJ;
4415                         res->klass = klass;
4416                 }
4417
4418                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4419
4420                 MONO_START_BB (cfg, end_bb);
4421
4422                 return res;
4423         } else {
4424                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4425                 if (!alloc)
4426                         return NULL;
4427
4428                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4429                 return alloc;
4430         }
4431 }
4432
4433 static gboolean
4434 mini_class_has_reference_variant_generic_argument (MonoCompile *cfg, MonoClass *klass, int context_used)
4435 {
4436         int i;
4437         MonoGenericContainer *container;
4438         MonoGenericInst *ginst;
4439
4440         if (mono_class_is_ginst (klass)) {
4441                 container = mono_class_get_generic_container (mono_class_get_generic_class (klass)->container_class);
4442                 ginst = mono_class_get_generic_class (klass)->context.class_inst;
4443         } else if (mono_class_is_gtd (klass) && context_used) {
4444                 container = mono_class_get_generic_container (klass);
4445                 ginst = container->context.class_inst;
4446         } else {
4447                 return FALSE;
4448         }
4449
4450         for (i = 0; i < container->type_argc; ++i) {
4451                 MonoType *type;
4452                 if (!(mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT)))
4453                         continue;
4454                 type = ginst->type_argv [i];
4455                 if (mini_type_is_reference (type))
4456                         return TRUE;
4457         }
4458         return FALSE;
4459 }
4460
4461 static GHashTable* direct_icall_type_hash;
4462
4463 static gboolean
4464 icall_is_direct_callable (MonoCompile *cfg, MonoMethod *cmethod)
4465 {
4466         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
4467         if (!direct_icalls_enabled (cfg))
4468                 return FALSE;
4469
4470         /*
4471          * An icall is directly callable if it doesn't directly or indirectly call mono_raise_exception ().
4472          * Whitelist a few icalls for now.
4473          */
4474         if (!direct_icall_type_hash) {
4475                 GHashTable *h = g_hash_table_new (g_str_hash, g_str_equal);
4476
4477                 g_hash_table_insert (h, (char*)"Decimal", GUINT_TO_POINTER (1));
4478                 g_hash_table_insert (h, (char*)"Number", GUINT_TO_POINTER (1));
4479                 g_hash_table_insert (h, (char*)"Buffer", GUINT_TO_POINTER (1));
4480                 g_hash_table_insert (h, (char*)"Monitor", GUINT_TO_POINTER (1));
4481                 mono_memory_barrier ();
4482                 direct_icall_type_hash = h;
4483         }
4484
4485         if (cmethod->klass == mono_defaults.math_class)
4486                 return TRUE;
4487         /* No locking needed */
4488         if (cmethod->klass->image == mono_defaults.corlib && g_hash_table_lookup (direct_icall_type_hash, cmethod->klass->name))
4489                 return TRUE;
4490         return FALSE;
4491 }
4492
4493 static gboolean
4494 method_needs_stack_walk (MonoCompile *cfg, MonoMethod *cmethod)
4495 {
4496         if (cmethod->klass == mono_defaults.systemtype_class) {
4497                 if (!strcmp (cmethod->name, "GetType"))
4498                         return TRUE;
4499         }
4500         return FALSE;
4501 }
4502
4503 #define is_complex_isinst(klass) (mono_class_is_interface (klass) || klass->rank || mono_class_is_nullable (klass) || mono_class_is_marshalbyref (klass) || mono_class_is_sealed (klass) || klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR)
4504
4505 static MonoInst*
4506 emit_isinst_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args)
4507 {
4508         MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
4509         return mono_emit_method_call (cfg, mono_isinst, args, NULL);
4510 }
4511
4512 static MonoInst*
4513 emit_castclass_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args)
4514 {
4515         MonoMethod *mono_castclass = mono_marshal_get_castclass_with_cache ();
4516         MonoInst *res;
4517
4518         save_cast_details (cfg, klass, args [0]->dreg, TRUE);
4519         res = mono_emit_method_call (cfg, mono_castclass, args, NULL);
4520         reset_cast_details (cfg);
4521
4522         return res;
4523 }
4524
4525 static int
4526 get_castclass_cache_idx (MonoCompile *cfg)
4527 {
4528         /* Each CASTCLASS_CACHE patch needs a unique index which identifies the call site */
4529         cfg->castclass_cache_index ++;
4530         return (cfg->method_index << 16) | cfg->castclass_cache_index;
4531 }
4532
4533
4534 static MonoInst*
4535 emit_isinst_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass)
4536 {
4537         MonoInst *args [3];
4538         int idx;
4539
4540         args [0] = obj; /* obj */
4541         EMIT_NEW_CLASSCONST (cfg, args [1], klass); /* klass */
4542
4543         idx = get_castclass_cache_idx (cfg); /* inline cache*/
4544         args [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
4545
4546         return emit_isinst_with_cache (cfg, klass, args);
4547 }
4548
4549 static MonoInst*
4550 emit_castclass_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass)
4551 {
4552         MonoInst *args [3];
4553         int idx;
4554
4555         /* obj */
4556         args [0] = obj;
4557
4558         /* klass */
4559         EMIT_NEW_CLASSCONST (cfg, args [1], klass);
4560
4561         /* inline cache*/
4562         idx = get_castclass_cache_idx (cfg);
4563         args [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
4564
4565         /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
4566         return emit_castclass_with_cache (cfg, klass, args);
4567 }
4568
4569 /*
4570  * Returns NULL and set the cfg exception on error.
4571  */
4572 static MonoInst*
4573 handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
4574 {
4575         MonoBasicBlock *is_null_bb;
4576         int obj_reg = src->dreg;
4577         int vtable_reg = alloc_preg (cfg);
4578         MonoInst *klass_inst = NULL;
4579
4580         if (MONO_INS_IS_PCONST_NULL (src))
4581                 return src;
4582
4583         if (context_used) {
4584                 MonoInst *args [3];
4585
4586                 if (mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4587                         MonoInst *cache_ins;
4588
4589                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4590
4591                         /* obj */
4592                         args [0] = src;
4593
4594                         /* klass - it's the second element of the cache entry*/
4595                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4596
4597                         /* cache */
4598                         args [2] = cache_ins;
4599
4600                         return emit_castclass_with_cache (cfg, klass, args);
4601                 }
4602
4603                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4604         }
4605
4606         NEW_BBLOCK (cfg, is_null_bb);
4607
4608         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4609         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
4610
4611         save_cast_details (cfg, klass, obj_reg, FALSE);
4612
4613         if (mono_class_is_interface (klass)) {
4614                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4615                 mini_emit_iface_cast (cfg, vtable_reg, klass, NULL, NULL);
4616         } else {
4617                 int klass_reg = alloc_preg (cfg);
4618
4619                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4620
4621                 if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && mono_class_is_sealed (klass)) {
4622                         /* the remoting code is broken, access the class for now */
4623                         if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4624                                 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4625                                 if (!vt) {
4626                                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4627                                         cfg->exception_ptr = klass;
4628                                         return NULL;
4629                                 }
4630                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4631                         } else {
4632                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4633                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4634                         }
4635                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4636                 } else {
4637                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4638                         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
4639                 }
4640         }
4641
4642         MONO_START_BB (cfg, is_null_bb);
4643
4644         reset_cast_details (cfg);
4645
4646         return src;
4647 }
4648
4649 /*
4650  * Returns NULL and set the cfg exception on error.
4651  */
4652 static MonoInst*
4653 handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
4654 {
4655         MonoInst *ins;
4656         MonoBasicBlock *is_null_bb, *false_bb, *end_bb;
4657         int obj_reg = src->dreg;
4658         int vtable_reg = alloc_preg (cfg);
4659         int res_reg = alloc_ireg_ref (cfg);
4660         MonoInst *klass_inst = NULL;
4661
4662         if (context_used) {
4663                 MonoInst *args [3];
4664
4665                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4666                         MonoInst *cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4667
4668                         args [0] = src; /* obj */
4669
4670                         /* klass - it's the second element of the cache entry*/
4671                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4672
4673                         args [2] = cache_ins; /* cache */
4674                         return emit_isinst_with_cache (cfg, klass, args);
4675                 }
4676
4677                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4678         }
4679
4680         NEW_BBLOCK (cfg, is_null_bb);
4681         NEW_BBLOCK (cfg, false_bb);
4682         NEW_BBLOCK (cfg, end_bb);
4683
4684         /* Do the assignment at the beginning, so the other assignment can be if converted */
4685         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, res_reg, obj_reg);
4686         ins->type = STACK_OBJ;
4687         ins->klass = klass;
4688
4689         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4690         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_null_bb);
4691
4692         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4693
4694         if (mono_class_is_interface (klass)) {
4695                 g_assert (!context_used);
4696                 /* the is_null_bb target simply copies the input register to the output */
4697                 mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb);
4698         } else {
4699                 int klass_reg = alloc_preg (cfg);
4700
4701                 if (klass->rank) {
4702                         int rank_reg = alloc_preg (cfg);
4703                         int eclass_reg = alloc_preg (cfg);
4704
4705                         g_assert (!context_used);
4706                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
4707                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
4708                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4709                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4710                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
4711                         if (klass->cast_class == mono_defaults.object_class) {
4712                                 int parent_reg = alloc_preg (cfg);
4713                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
4714                                 mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, is_null_bb);
4715                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4716                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4717                         } else if (klass->cast_class == mono_defaults.enum_class->parent) {
4718                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, is_null_bb);
4719                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);                          
4720                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4721                         } else if (klass->cast_class == mono_defaults.enum_class) {
4722                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4723                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4724                         } else if (mono_class_is_interface (klass->cast_class)) {
4725                                 mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4726                         } else {
4727                                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) {
4728                                         /* Check that the object is a vector too */
4729                                         int bounds_reg = alloc_preg (cfg);
4730                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
4731                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
4732                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4733                                 }
4734
4735                                 /* the is_null_bb target simply copies the input register to the output */
4736                                 mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4737                         }
4738                 } else if (mono_class_is_nullable (klass)) {
4739                         g_assert (!context_used);
4740                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4741                         /* the is_null_bb target simply copies the input register to the output */
4742                         mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
4743                 } else {
4744                         if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && mono_class_is_sealed (klass)) {
4745                                 g_assert (!context_used);
4746                                 /* the remoting code is broken, access the class for now */
4747                                 if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4748                                         MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4749                                         if (!vt) {
4750                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4751                                                 cfg->exception_ptr = klass;
4752                                                 return NULL;
4753                                         }
4754                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4755                                 } else {
4756                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4757                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4758                                 }
4759                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4760                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
4761                         } else {
4762                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4763                                 /* the is_null_bb target simply copies the input register to the output */
4764                                 mini_emit_isninst_cast_inst (cfg, klass_reg, klass, klass_inst, false_bb, is_null_bb);
4765                         }
4766                 }
4767         }
4768
4769         MONO_START_BB (cfg, false_bb);
4770
4771         MONO_EMIT_NEW_PCONST (cfg, res_reg, 0);
4772         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4773
4774         MONO_START_BB (cfg, is_null_bb);
4775
4776         MONO_START_BB (cfg, end_bb);
4777
4778         return ins;
4779 }
4780
4781 static MonoInst*
4782 handle_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4783 {
4784         /* This opcode takes as input an object reference and a class, and returns:
4785         0) if the object is an instance of the class,
4786         1) if the object is not instance of the class,
4787         2) if the object is a proxy whose type cannot be determined */
4788
4789         MonoInst *ins;
4790 #ifndef DISABLE_REMOTING
4791         MonoBasicBlock *true_bb, *false_bb, *false2_bb, *end_bb, *no_proxy_bb, *interface_fail_bb;
4792 #else
4793         MonoBasicBlock *true_bb, *false_bb, *end_bb;
4794 #endif
4795         int obj_reg = src->dreg;
4796         int dreg = alloc_ireg (cfg);
4797         int tmp_reg;
4798 #ifndef DISABLE_REMOTING
4799         int klass_reg = alloc_preg (cfg);
4800 #endif
4801
4802         NEW_BBLOCK (cfg, true_bb);
4803         NEW_BBLOCK (cfg, false_bb);
4804         NEW_BBLOCK (cfg, end_bb);
4805 #ifndef DISABLE_REMOTING
4806         NEW_BBLOCK (cfg, false2_bb);
4807         NEW_BBLOCK (cfg, no_proxy_bb);
4808 #endif
4809
4810         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4811         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
4812
4813         if (mono_class_is_interface (klass)) {
4814 #ifndef DISABLE_REMOTING
4815                 NEW_BBLOCK (cfg, interface_fail_bb);
4816 #endif
4817
4818                 tmp_reg = alloc_preg (cfg);
4819                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4820 #ifndef DISABLE_REMOTING
4821                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, true_bb);
4822                 MONO_START_BB (cfg, interface_fail_bb);
4823                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4824                 
4825                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, false_bb);
4826
4827                 tmp_reg = alloc_preg (cfg);
4828                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4829                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4830                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false2_bb);                
4831 #else
4832                 mini_emit_iface_cast (cfg, tmp_reg, klass, false_bb, true_bb);
4833 #endif
4834         } else {
4835 #ifndef DISABLE_REMOTING
4836                 tmp_reg = alloc_preg (cfg);
4837                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4838                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4839
4840                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4841                 tmp_reg = alloc_preg (cfg);
4842                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4843                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4844
4845                 tmp_reg = alloc_preg (cfg);             
4846                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4847                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4848                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4849                 
4850                 mini_emit_isninst_cast (cfg, klass_reg, klass, false2_bb, true_bb);
4851                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false2_bb);
4852
4853                 MONO_START_BB (cfg, no_proxy_bb);
4854
4855                 mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, true_bb);
4856 #else
4857                 g_error ("transparent proxy support is disabled while trying to JIT code that uses it");
4858 #endif
4859         }
4860
4861         MONO_START_BB (cfg, false_bb);
4862
4863         MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4864         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4865
4866 #ifndef DISABLE_REMOTING
4867         MONO_START_BB (cfg, false2_bb);
4868
4869         MONO_EMIT_NEW_ICONST (cfg, dreg, 2);
4870         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4871 #endif
4872
4873         MONO_START_BB (cfg, true_bb);
4874
4875         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4876
4877         MONO_START_BB (cfg, end_bb);
4878
4879         /* FIXME: */
4880         MONO_INST_NEW (cfg, ins, OP_ICONST);
4881         ins->dreg = dreg;
4882         ins->type = STACK_I4;
4883
4884         return ins;
4885 }
4886
4887 static MonoInst*
4888 handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4889 {
4890         /* This opcode takes as input an object reference and a class, and returns:
4891         0) if the object is an instance of the class,
4892         1) if the object is a proxy whose type cannot be determined
4893         an InvalidCastException exception is thrown otherwhise*/
4894         
4895         MonoInst *ins;
4896 #ifndef DISABLE_REMOTING
4897         MonoBasicBlock *end_bb, *ok_result_bb, *no_proxy_bb, *interface_fail_bb, *fail_1_bb;
4898 #else
4899         MonoBasicBlock *ok_result_bb;
4900 #endif
4901         int obj_reg = src->dreg;
4902         int dreg = alloc_ireg (cfg);
4903         int tmp_reg = alloc_preg (cfg);
4904
4905 #ifndef DISABLE_REMOTING
4906         int klass_reg = alloc_preg (cfg);
4907         NEW_BBLOCK (cfg, end_bb);
4908 #endif
4909
4910         NEW_BBLOCK (cfg, ok_result_bb);
4911
4912         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4913         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, ok_result_bb);
4914
4915         save_cast_details (cfg, klass, obj_reg, FALSE);
4916
4917         if (mono_class_is_interface (klass)) {
4918 #ifndef DISABLE_REMOTING
4919                 NEW_BBLOCK (cfg, interface_fail_bb);
4920         
4921                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4922                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, ok_result_bb);
4923                 MONO_START_BB (cfg, interface_fail_bb);
4924                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4925
4926                 mini_emit_class_check (cfg, klass_reg, mono_defaults.transparent_proxy_class);
4927
4928                 tmp_reg = alloc_preg (cfg);             
4929                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4930                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4931                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
4932                 
4933                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4934                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4935 #else
4936                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4937                 mini_emit_iface_cast (cfg, tmp_reg, klass, NULL, NULL);
4938                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, ok_result_bb);
4939 #endif
4940         } else {
4941 #ifndef DISABLE_REMOTING
4942                 NEW_BBLOCK (cfg, no_proxy_bb);
4943
4944                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4945                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4946                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4947
4948                 tmp_reg = alloc_preg (cfg);
4949                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4950                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4951
4952                 tmp_reg = alloc_preg (cfg);
4953                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4954                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4955                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4956
4957                 NEW_BBLOCK (cfg, fail_1_bb);
4958                 
4959                 mini_emit_isninst_cast (cfg, klass_reg, klass, fail_1_bb, ok_result_bb);
4960
4961                 MONO_START_BB (cfg, fail_1_bb);
4962
4963                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4964                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4965
4966                 MONO_START_BB (cfg, no_proxy_bb);
4967
4968                 mini_emit_castclass (cfg, obj_reg, klass_reg, klass, ok_result_bb);
4969 #else
4970                 g_error ("Transparent proxy support is disabled while trying to JIT code that uses it");
4971 #endif
4972         }
4973
4974         MONO_START_BB (cfg, ok_result_bb);
4975
4976         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4977
4978 #ifndef DISABLE_REMOTING
4979         MONO_START_BB (cfg, end_bb);
4980 #endif
4981
4982         /* FIXME: */
4983         MONO_INST_NEW (cfg, ins, OP_ICONST);
4984         ins->dreg = dreg;
4985         ins->type = STACK_I4;
4986
4987         return ins;
4988 }
4989
4990 static G_GNUC_UNUSED MonoInst*
4991 handle_enum_has_flag (MonoCompile *cfg, MonoClass *klass, MonoInst *enum_this, MonoInst *enum_flag)
4992 {
4993         MonoType *enum_type = mono_type_get_underlying_type (&klass->byval_arg);
4994         guint32 load_opc = mono_type_to_load_membase (cfg, enum_type);
4995         gboolean is_i4;
4996
4997         switch (enum_type->type) {
4998         case MONO_TYPE_I8:
4999         case MONO_TYPE_U8:
5000 #if SIZEOF_REGISTER == 8
5001         case MONO_TYPE_I:
5002         case MONO_TYPE_U:
5003 #endif
5004                 is_i4 = FALSE;
5005                 break;
5006         default:
5007                 is_i4 = TRUE;
5008                 break;
5009         }
5010
5011         {
5012                 MonoInst *load, *and_, *cmp, *ceq;
5013                 int enum_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
5014                 int and_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
5015                 int dest_reg = alloc_ireg (cfg);
5016
5017                 EMIT_NEW_LOAD_MEMBASE (cfg, load, load_opc, enum_reg, enum_this->dreg, 0);
5018                 EMIT_NEW_BIALU (cfg, and_, is_i4 ? OP_IAND : OP_LAND, and_reg, enum_reg, enum_flag->dreg);
5019                 EMIT_NEW_BIALU (cfg, cmp, is_i4 ? OP_ICOMPARE : OP_LCOMPARE, -1, and_reg, enum_flag->dreg);
5020                 EMIT_NEW_UNALU (cfg, ceq, is_i4 ? OP_ICEQ : OP_LCEQ, dest_reg, -1);
5021
5022                 ceq->type = STACK_I4;
5023
5024                 if (!is_i4) {
5025                         load = mono_decompose_opcode (cfg, load);
5026                         and_ = mono_decompose_opcode (cfg, and_);
5027                         cmp = mono_decompose_opcode (cfg, cmp);
5028                         ceq = mono_decompose_opcode (cfg, ceq);
5029                 }
5030
5031                 return ceq;
5032         }
5033 }
5034
5035 /*
5036  * Returns NULL and set the cfg exception on error.
5037  */
5038 static G_GNUC_UNUSED MonoInst*
5039 handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used, gboolean virtual_)
5040 {
5041         MonoInst *ptr;
5042         int dreg;
5043         gpointer trampoline;
5044         MonoInst *obj, *method_ins, *tramp_ins;
5045         MonoDomain *domain;
5046         guint8 **code_slot;
5047
5048         if (virtual_ && !cfg->llvm_only) {
5049                 MonoMethod *invoke = mono_get_delegate_invoke (klass);
5050                 g_assert (invoke);
5051
5052                 if (!mono_get_delegate_virtual_invoke_impl (mono_method_signature (invoke), context_used ? NULL : method))
5053                         return NULL;
5054         }
5055
5056         obj = handle_alloc (cfg, klass, FALSE, mono_class_check_context_used (klass));
5057         if (!obj)
5058                 return NULL;
5059
5060         /* Inline the contents of mono_delegate_ctor */
5061
5062         /* Set target field */
5063         /* Optimize away setting of NULL target */
5064         if (!MONO_INS_IS_PCONST_NULL (target)) {
5065                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
5066                 if (cfg->gen_write_barriers) {
5067                         dreg = alloc_preg (cfg);
5068                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target));
5069                         emit_write_barrier (cfg, ptr, target);
5070                 }
5071         }
5072
5073         /* Set method field */
5074         method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
5075         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
5076
5077         /* 
5078          * To avoid looking up the compiled code belonging to the target method
5079          * in mono_delegate_trampoline (), we allocate a per-domain memory slot to
5080          * store it, and we fill it after the method has been compiled.
5081          */
5082         if (!method->dynamic && !(cfg->opt & MONO_OPT_SHARED)) {
5083                 MonoInst *code_slot_ins;
5084
5085                 if (context_used) {
5086                         code_slot_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD_DELEGATE_CODE);
5087                 } else {
5088                         domain = mono_domain_get ();
5089                         mono_domain_lock (domain);
5090                         if (!domain_jit_info (domain)->method_code_hash)
5091                                 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
5092                         code_slot = (guint8 **)g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
5093                         if (!code_slot) {
5094                                 code_slot = (guint8 **)mono_domain_alloc0 (domain, sizeof (gpointer));
5095                                 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
5096                         }
5097                         mono_domain_unlock (domain);
5098
5099                         code_slot_ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHOD_CODE_SLOT, method);
5100                 }
5101                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);                
5102         }
5103
5104         if (cfg->llvm_only) {
5105                 MonoInst *args [16];
5106
5107                 if (virtual_) {
5108                         args [0] = obj;
5109                         args [1] = target;
5110                         args [2] = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
5111                         mono_emit_jit_icall (cfg, mono_llvmonly_init_delegate_virtual, args);
5112                 } else {
5113                         args [0] = obj;
5114                         mono_emit_jit_icall (cfg, mono_llvmonly_init_delegate, args);
5115                 }
5116
5117                 return obj;
5118         }
5119
5120         if (cfg->compile_aot) {
5121                 MonoDelegateClassMethodPair *del_tramp;
5122
5123                 del_tramp = (MonoDelegateClassMethodPair *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoDelegateClassMethodPair));
5124                 del_tramp->klass = klass;
5125                 del_tramp->method = context_used ? NULL : method;
5126                 del_tramp->is_virtual = virtual_;
5127                 EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_DELEGATE_TRAMPOLINE, del_tramp);
5128         } else {
5129                 if (virtual_)
5130                         trampoline = mono_create_delegate_virtual_trampoline (cfg->domain, klass, context_used ? NULL : method);
5131                 else
5132                         trampoline = mono_create_delegate_trampoline_info (cfg->domain, klass, context_used ? NULL : method);
5133                 EMIT_NEW_PCONST (cfg, tramp_ins, trampoline);
5134         }
5135
5136         /* Set invoke_impl field */
5137         if (virtual_) {
5138                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), tramp_ins->dreg);
5139         } else {
5140                 dreg = alloc_preg (cfg);
5141                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, invoke_impl));
5142                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), dreg);
5143
5144                 dreg = alloc_preg (cfg);
5145                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, method_ptr));
5146                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), dreg);
5147         }
5148
5149         dreg = alloc_preg (cfg);
5150         MONO_EMIT_NEW_ICONST (cfg, dreg, virtual_ ? 1 : 0);
5151         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_is_virtual), dreg);
5152
5153         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
5154
5155         return obj;
5156 }
5157
5158 static MonoInst*
5159 handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
5160 {
5161         MonoJitICallInfo *info;
5162
5163         /* Need to register the icall so it gets an icall wrapper */
5164         info = mono_get_array_new_va_icall (rank);
5165
5166         cfg->flags |= MONO_CFG_HAS_VARARGS;
5167
5168         /* mono_array_new_va () needs a vararg calling convention */
5169         cfg->exception_message = g_strdup ("array-new");
5170         cfg->disable_llvm = TRUE;
5171
5172         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
5173         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
5174 }
5175
5176 /*
5177  * handle_constrained_gsharedvt_call:
5178  *
5179  *   Handle constrained calls where the receiver is a gsharedvt type.
5180  * Return the instruction representing the call. Set the cfg exception on failure.
5181  */
5182 static MonoInst*
5183 handle_constrained_gsharedvt_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp, MonoClass *constrained_class,
5184                                                                    gboolean *ref_emit_widen)
5185 {
5186         MonoInst *ins = NULL;
5187         gboolean emit_widen = *ref_emit_widen;
5188
5189         /*
5190          * Constrained calls need to behave differently at runtime dependending on whenever the receiver is instantiated as ref type or as a vtype.
5191          * 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
5192          * pack the arguments into an array, and do the rest of the work in in an icall.
5193          */
5194         if (((cmethod->klass == mono_defaults.object_class) || mono_class_is_interface (cmethod->klass) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) &&
5195                 (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)) &&
5196                 (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]))))) {
5197                 MonoInst *args [16];
5198
5199                 /*
5200                  * This case handles calls to
5201                  * - object:ToString()/Equals()/GetHashCode(),
5202                  * - System.IComparable<T>:CompareTo()
5203                  * - System.IEquatable<T>:Equals ()
5204                  * plus some simple interface calls enough to support AsyncTaskMethodBuilder.
5205                  */
5206
5207                 args [0] = sp [0];
5208                 if (mono_method_check_context_used (cmethod))
5209                         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cmethod), cmethod, MONO_RGCTX_INFO_METHOD);
5210                 else
5211                         EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
5212                 args [2] = emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_class), constrained_class, MONO_RGCTX_INFO_KLASS);
5213
5214                 /* !fsig->hasthis is for the wrapper for the Object.GetType () icall */
5215                 if (fsig->hasthis && fsig->param_count) {
5216                         /* Pass the arguments using a localloc-ed array using the format expected by runtime_invoke () */
5217                         MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
5218                         ins->dreg = alloc_preg (cfg);
5219                         ins->inst_imm = fsig->param_count * sizeof (mgreg_t);
5220                         MONO_ADD_INS (cfg->cbb, ins);
5221                         args [4] = ins;
5222
5223                         if (mini_is_gsharedvt_type (fsig->params [0])) {
5224                                 int addr_reg, deref_arg_reg;
5225
5226                                 ins = emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
5227                                 deref_arg_reg = alloc_preg (cfg);
5228                                 /* deref_arg = BOX_TYPE != MONO_GSHAREDVT_BOX_TYPE_VTYPE */
5229                                 EMIT_NEW_BIALU_IMM (cfg, args [3], OP_ISUB_IMM, deref_arg_reg, ins->dreg, 1);
5230
5231                                 EMIT_NEW_VARLOADA_VREG (cfg, ins, sp [1]->dreg, fsig->params [0]);
5232                                 addr_reg = ins->dreg;
5233                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, addr_reg);
5234                         } else {
5235                                 EMIT_NEW_ICONST (cfg, args [3], 0);
5236                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, sp [1]->dreg);
5237                         }
5238                 } else {
5239                         EMIT_NEW_ICONST (cfg, args [3], 0);
5240                         EMIT_NEW_ICONST (cfg, args [4], 0);
5241                 }
5242                 ins = mono_emit_jit_icall (cfg, mono_gsharedvt_constrained_call, args);
5243                 emit_widen = FALSE;
5244
5245                 if (mini_is_gsharedvt_type (fsig->ret)) {
5246                         ins = handle_unbox_gsharedvt (cfg, mono_class_from_mono_type (fsig->ret), ins);
5247                 } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret)) {
5248                         MonoInst *add;
5249
5250                         /* Unbox */
5251                         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), ins->dreg, sizeof (MonoObject));
5252                         MONO_ADD_INS (cfg->cbb, add);
5253                         /* Load value */
5254                         NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, add->dreg, 0);
5255                         MONO_ADD_INS (cfg->cbb, ins);
5256                         /* ins represents the call result */
5257                 }
5258         } else {
5259                 GSHAREDVT_FAILURE (CEE_CALLVIRT);
5260         }
5261
5262         *ref_emit_widen = emit_widen;
5263
5264         return ins;
5265
5266  exception_exit:
5267         return NULL;
5268 }
5269
5270 static void
5271 mono_emit_load_got_addr (MonoCompile *cfg)
5272 {
5273         MonoInst *getaddr, *dummy_use;
5274
5275         if (!cfg->got_var || cfg->got_var_allocated)
5276                 return;
5277
5278         MONO_INST_NEW (cfg, getaddr, OP_LOAD_GOTADDR);
5279         getaddr->cil_code = cfg->header->code;
5280         getaddr->dreg = cfg->got_var->dreg;
5281
5282         /* Add it to the start of the first bblock */
5283         if (cfg->bb_entry->code) {
5284                 getaddr->next = cfg->bb_entry->code;
5285                 cfg->bb_entry->code = getaddr;
5286         }
5287         else
5288                 MONO_ADD_INS (cfg->bb_entry, getaddr);
5289
5290         cfg->got_var_allocated = TRUE;
5291
5292         /* 
5293          * Add a dummy use to keep the got_var alive, since real uses might
5294          * only be generated by the back ends.
5295          * Add it to end_bblock, so the variable's lifetime covers the whole
5296          * method.
5297          * It would be better to make the usage of the got var explicit in all
5298          * cases when the backend needs it (i.e. calls, throw etc.), so this
5299          * wouldn't be needed.
5300          */
5301         NEW_DUMMY_USE (cfg, dummy_use, cfg->got_var);
5302         MONO_ADD_INS (cfg->bb_exit, dummy_use);
5303 }
5304
5305 static int inline_limit;
5306 static gboolean inline_limit_inited;
5307
5308 static gboolean
5309 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
5310 {
5311         MonoMethodHeaderSummary header;
5312         MonoVTable *vtable;
5313 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5314         MonoMethodSignature *sig = mono_method_signature (method);
5315         int i;
5316 #endif
5317
5318         if (cfg->disable_inline)
5319                 return FALSE;
5320         if (cfg->gshared)
5321                 return FALSE;
5322
5323         if (cfg->inline_depth > 10)
5324                 return FALSE;
5325
5326         if (!mono_method_get_header_summary (method, &header))
5327                 return FALSE;
5328
5329         /*runtime, icall and pinvoke are checked by summary call*/
5330         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
5331             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
5332             (mono_class_is_marshalbyref (method->klass)) ||
5333             header.has_clauses)
5334                 return FALSE;
5335
5336         /* also consider num_locals? */
5337         /* Do the size check early to avoid creating vtables */
5338         if (!inline_limit_inited) {
5339                 if (g_getenv ("MONO_INLINELIMIT"))
5340                         inline_limit = atoi (g_getenv ("MONO_INLINELIMIT"));
5341                 else
5342                         inline_limit = INLINE_LENGTH_LIMIT;
5343                 inline_limit_inited = TRUE;
5344         }
5345         if (header.code_size >= inline_limit && !(method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
5346                 return FALSE;
5347
5348         /*
5349          * if we can initialize the class of the method right away, we do,
5350          * otherwise we don't allow inlining if the class needs initialization,
5351          * since it would mean inserting a call to mono_runtime_class_init()
5352          * inside the inlined code
5353          */
5354         if (!(cfg->opt & MONO_OPT_SHARED)) {
5355                 /* The AggressiveInlining hint is a good excuse to force that cctor to run. */
5356                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING) {
5357                         vtable = mono_class_vtable (cfg->domain, method->klass);
5358                         if (!vtable)
5359                                 return FALSE;
5360                         if (!cfg->compile_aot) {
5361                                 MonoError error;
5362                                 if (!mono_runtime_class_init_full (vtable, &error)) {
5363                                         mono_error_cleanup (&error);
5364                                         return FALSE;
5365                                 }
5366                         }
5367                 } else if (mono_class_is_before_field_init (method->klass)) {
5368                         if (cfg->run_cctors && method->klass->has_cctor) {
5369                                 /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
5370                                 if (!method->klass->runtime_info)
5371                                         /* No vtable created yet */
5372                                         return FALSE;
5373                                 vtable = mono_class_vtable (cfg->domain, method->klass);
5374                                 if (!vtable)
5375                                         return FALSE;
5376                                 /* This makes so that inline cannot trigger */
5377                                 /* .cctors: too many apps depend on them */
5378                                 /* running with a specific order... */
5379                                 if (! vtable->initialized)
5380                                         return FALSE;
5381                                 MonoError error;
5382                                 if (!mono_runtime_class_init_full (vtable, &error)) {
5383                                         mono_error_cleanup (&error);
5384                                         return FALSE;
5385                                 }
5386                         }
5387                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
5388                         if (!method->klass->runtime_info)
5389                                 /* No vtable created yet */
5390                                 return FALSE;
5391                         vtable = mono_class_vtable (cfg->domain, method->klass);
5392                         if (!vtable)
5393                                 return FALSE;
5394                         if (!vtable->initialized)
5395                                 return FALSE;
5396                 }
5397         } else {
5398                 /* 
5399                  * If we're compiling for shared code
5400                  * the cctor will need to be run at aot method load time, for example,
5401                  * or at the end of the compilation of the inlining method.
5402                  */
5403                 if (mono_class_needs_cctor_run (method->klass, NULL) && !mono_class_is_before_field_init (method->klass))
5404                         return FALSE;
5405         }
5406
5407 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5408         if (mono_arch_is_soft_float ()) {
5409                 /* FIXME: */
5410                 if (sig->ret && sig->ret->type == MONO_TYPE_R4)
5411                         return FALSE;
5412                 for (i = 0; i < sig->param_count; ++i)
5413                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
5414                                 return FALSE;
5415         }
5416 #endif
5417
5418         if (g_list_find (cfg->dont_inline, method))
5419                 return FALSE;
5420
5421         return TRUE;
5422 }
5423
5424 static gboolean
5425 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoClass *klass, MonoVTable *vtable)
5426 {
5427         if (!cfg->compile_aot) {
5428                 g_assert (vtable);
5429                 if (vtable->initialized)
5430                         return FALSE;
5431         }
5432
5433         if (mono_class_is_before_field_init (klass)) {
5434                 if (cfg->method == method)
5435                         return FALSE;
5436         }
5437
5438         if (!mono_class_needs_cctor_run (klass, method))
5439                 return FALSE;
5440
5441         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (klass == method->klass))
5442                 /* The initialization is already done before the method is called */
5443                 return FALSE;
5444
5445         return TRUE;
5446 }
5447
5448 MonoInst*
5449 mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
5450 {
5451         MonoInst *ins;
5452         guint32 size;
5453         int mult_reg, add_reg, array_reg, index_reg, index2_reg;
5454         int context_used;
5455
5456         if (mini_is_gsharedvt_variable_klass (klass)) {
5457                 size = -1;
5458         } else {
5459                 mono_class_init (klass);
5460                 size = mono_class_array_element_size (klass);
5461         }
5462
5463         mult_reg = alloc_preg (cfg);
5464         array_reg = arr->dreg;
5465         index_reg = index->dreg;
5466
5467 #if SIZEOF_REGISTER == 8
5468         /* The array reg is 64 bits but the index reg is only 32 */
5469         if (COMPILE_LLVM (cfg)) {
5470                 /* Not needed */
5471                 index2_reg = index_reg;
5472         } else {
5473                 index2_reg = alloc_preg (cfg);
5474                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
5475         }
5476 #else
5477         if (index->type == STACK_I8) {
5478                 index2_reg = alloc_preg (cfg);
5479                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I4, index2_reg, index_reg);
5480         } else {
5481                 index2_reg = index_reg;
5482         }
5483 #endif
5484
5485         if (bcheck)
5486                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
5487
5488 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5489         if (size == 1 || size == 2 || size == 4 || size == 8) {
5490                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
5491
5492                 EMIT_NEW_X86_LEA (cfg, ins, array_reg, index2_reg, fast_log2 [size], MONO_STRUCT_OFFSET (MonoArray, vector));
5493                 ins->klass = mono_class_get_element_class (klass);
5494                 ins->type = STACK_MP;
5495
5496                 return ins;
5497         }
5498 #endif          
5499
5500         add_reg = alloc_ireg_mp (cfg);
5501
5502         if (size == -1) {
5503                 MonoInst *rgctx_ins;
5504
5505                 /* gsharedvt */
5506                 g_assert (cfg->gshared);
5507                 context_used = mini_class_check_context_used (cfg, klass);
5508                 g_assert (context_used);
5509                 rgctx_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE);
5510                 MONO_EMIT_NEW_BIALU (cfg, OP_IMUL, mult_reg, index2_reg, rgctx_ins->dreg);
5511         } else {
5512                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
5513         }
5514         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
5515         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5516         ins->klass = mono_class_get_element_class (klass);
5517         ins->type = STACK_MP;
5518         MONO_ADD_INS (cfg->cbb, ins);
5519
5520         return ins;
5521 }
5522
5523 static MonoInst*
5524 mini_emit_ldelema_2_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index_ins1, MonoInst *index_ins2)
5525 {
5526         int bounds_reg = alloc_preg (cfg);
5527         int add_reg = alloc_ireg_mp (cfg);
5528         int mult_reg = alloc_preg (cfg);
5529         int mult2_reg = alloc_preg (cfg);
5530         int low1_reg = alloc_preg (cfg);
5531         int low2_reg = alloc_preg (cfg);
5532         int high1_reg = alloc_preg (cfg);
5533         int high2_reg = alloc_preg (cfg);
5534         int realidx1_reg = alloc_preg (cfg);
5535         int realidx2_reg = alloc_preg (cfg);
5536         int sum_reg = alloc_preg (cfg);
5537         int index1, index2, tmpreg;
5538         MonoInst *ins;
5539         guint32 size;
5540
5541         mono_class_init (klass);
5542         size = mono_class_array_element_size (klass);
5543
5544         index1 = index_ins1->dreg;
5545         index2 = index_ins2->dreg;
5546
5547 #if SIZEOF_REGISTER == 8
5548         /* The array reg is 64 bits but the index reg is only 32 */
5549         if (COMPILE_LLVM (cfg)) {
5550                 /* Not needed */
5551         } else {
5552                 tmpreg = alloc_preg (cfg);
5553                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index1);
5554                 index1 = tmpreg;
5555                 tmpreg = alloc_preg (cfg);
5556                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index2);
5557                 index2 = tmpreg;
5558         }
5559 #else
5560         // FIXME: Do we need to do something here for i8 indexes, like in ldelema_1_ins ?
5561         tmpreg = -1;
5562 #endif
5563
5564         /* range checking */
5565         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, 
5566                                        arr->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5567
5568         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low1_reg, 
5569                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5570         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx1_reg, index1, low1_reg);
5571         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high1_reg, 
5572                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5573         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high1_reg, realidx1_reg);
5574         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5575
5576         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low2_reg, 
5577                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5578         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx2_reg, index2, low2_reg);
5579         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high2_reg, 
5580                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5581         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high2_reg, realidx2_reg);
5582         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5583
5584         MONO_EMIT_NEW_BIALU (cfg, OP_PMUL, mult_reg, high2_reg, realidx1_reg);
5585         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, mult_reg, realidx2_reg);
5586         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PMUL_IMM, mult2_reg, sum_reg, size);
5587         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult2_reg, arr->dreg);
5588         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5589
5590         ins->type = STACK_MP;
5591         ins->klass = klass;
5592         MONO_ADD_INS (cfg->cbb, ins);
5593
5594         return ins;
5595 }
5596
5597 static MonoInst*
5598 mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
5599 {
5600         int rank;
5601         MonoInst *addr;
5602         MonoMethod *addr_method;
5603         int element_size;
5604         MonoClass *eclass = cmethod->klass->element_class;
5605
5606         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
5607
5608         if (rank == 1)
5609                 return mini_emit_ldelema_1_ins (cfg, eclass, sp [0], sp [1], TRUE);
5610
5611         /* emit_ldelema_2 depends on OP_LMUL */
5612         if (!cfg->backend->emulate_mul_div && rank == 2 && (cfg->opt & MONO_OPT_INTRINS) && !mini_is_gsharedvt_variable_klass (eclass)) {
5613                 return mini_emit_ldelema_2_ins (cfg, eclass, sp [0], sp [1], sp [2]);
5614         }
5615
5616         if (mini_is_gsharedvt_variable_klass (eclass))
5617                 element_size = 0;
5618         else
5619                 element_size = mono_class_array_element_size (eclass);
5620         addr_method = mono_marshal_get_array_address (rank, element_size);
5621         addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
5622
5623         return addr;
5624 }
5625
5626 static MonoBreakPolicy
5627 always_insert_breakpoint (MonoMethod *method)
5628 {
5629         return MONO_BREAK_POLICY_ALWAYS;
5630 }
5631
5632 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
5633
5634 /**
5635  * mono_set_break_policy:
5636  * policy_callback: the new callback function
5637  *
5638  * Allow embedders to decide wherther to actually obey breakpoint instructions
5639  * (both break IL instructions and Debugger.Break () method calls), for example
5640  * to not allow an app to be aborted by a perfectly valid IL opcode when executing
5641  * untrusted or semi-trusted code.
5642  *
5643  * @policy_callback will be called every time a break point instruction needs to
5644  * be inserted with the method argument being the method that calls Debugger.Break()
5645  * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
5646  * if it wants the breakpoint to not be effective in the given method.
5647  * #MONO_BREAK_POLICY_ALWAYS is the default.
5648  */
5649 void
5650 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
5651 {
5652         if (policy_callback)
5653                 break_policy_func = policy_callback;
5654         else
5655                 break_policy_func = always_insert_breakpoint;
5656 }
5657
5658 static gboolean
5659 should_insert_brekpoint (MonoMethod *method) {
5660         switch (break_policy_func (method)) {
5661         case MONO_BREAK_POLICY_ALWAYS:
5662                 return TRUE;
5663         case MONO_BREAK_POLICY_NEVER:
5664                 return FALSE;
5665         case MONO_BREAK_POLICY_ON_DBG:
5666                 g_warning ("mdb no longer supported");
5667                 return FALSE;
5668         default:
5669                 g_warning ("Incorrect value returned from break policy callback");
5670                 return FALSE;
5671         }
5672 }
5673
5674 /* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
5675 static MonoInst*
5676 emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5677 {
5678         MonoInst *addr, *store, *load;
5679         MonoClass *eklass = mono_class_from_mono_type (fsig->params [2]);
5680
5681         /* the bounds check is already done by the callers */
5682         addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5683         if (is_set) {
5684                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
5685                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
5686                 if (mini_type_is_reference (&eklass->byval_arg))
5687                         emit_write_barrier (cfg, addr, load);
5688         } else {
5689                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
5690                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
5691         }
5692         return store;
5693 }
5694
5695
5696 static gboolean
5697 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
5698 {
5699         return mini_type_is_reference (&klass->byval_arg);
5700 }
5701
5702 static MonoInst*
5703 emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean safety_checks)
5704 {
5705         if (safety_checks && generic_class_is_reference_type (cfg, klass) &&
5706                 !(MONO_INS_IS_PCONST_NULL (sp [2]))) {
5707                 MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
5708                 MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
5709                 MonoInst *iargs [3];
5710
5711                 if (!helper->slot)
5712                         mono_class_setup_vtable (obj_array);
5713                 g_assert (helper->slot);
5714
5715                 if (sp [0]->type != STACK_OBJ)
5716                         return NULL;
5717                 if (sp [2]->type != STACK_OBJ)
5718                         return NULL;
5719
5720                 iargs [2] = sp [2];
5721                 iargs [1] = sp [1];
5722                 iargs [0] = sp [0];
5723
5724                 return mono_emit_method_call (cfg, helper, iargs, sp [0]);
5725         } else {
5726                 MonoInst *ins;
5727
5728                 if (mini_is_gsharedvt_variable_klass (klass)) {
5729                         MonoInst *addr;
5730
5731                         // FIXME-VT: OP_ICONST optimization
5732                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
5733                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5734                         ins->opcode = OP_STOREV_MEMBASE;
5735                 } else if (sp [1]->opcode == OP_ICONST) {
5736                         int array_reg = sp [0]->dreg;
5737                         int index_reg = sp [1]->dreg;
5738                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
5739
5740                         if (SIZEOF_REGISTER == 8 && COMPILE_LLVM (cfg))
5741                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, index_reg);
5742
5743                         if (safety_checks)
5744                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
5745                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
5746                 } else {
5747                         MonoInst *addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], safety_checks);
5748                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5749                         if (generic_class_is_reference_type (cfg, klass))
5750                                 emit_write_barrier (cfg, addr, sp [2]);
5751                 }
5752                 return ins;
5753         }
5754 }
5755
5756 static MonoInst*
5757 emit_array_unsafe_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5758 {
5759         MonoClass *eklass;
5760         
5761         if (is_set)
5762                 eklass = mono_class_from_mono_type (fsig->params [2]);
5763         else
5764                 eklass = mono_class_from_mono_type (fsig->ret);
5765
5766         if (is_set) {
5767                 return emit_array_store (cfg, eklass, args, FALSE);
5768         } else {
5769                 MonoInst *ins, *addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5770                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &eklass->byval_arg, addr->dreg, 0);
5771                 return ins;
5772         }
5773 }
5774
5775 static gboolean
5776 is_unsafe_mov_compatible (MonoCompile *cfg, MonoClass *param_klass, MonoClass *return_klass)
5777 {
5778         uint32_t align;
5779         int param_size, return_size;
5780
5781         param_klass = mono_class_from_mono_type (mini_get_underlying_type (&param_klass->byval_arg));
5782         return_klass = mono_class_from_mono_type (mini_get_underlying_type (&return_klass->byval_arg));
5783
5784         if (cfg->verbose_level > 3)
5785                 printf ("[UNSAFE-MOV-INTRISIC] %s <- %s\n", return_klass->name, param_klass->name);
5786
5787         //Don't allow mixing reference types with value types
5788         if (param_klass->valuetype != return_klass->valuetype) {
5789                 if (cfg->verbose_level > 3)
5790                         printf ("[UNSAFE-MOV-INTRISIC]\tone of the args is a valuetype and the other is not\n");
5791                 return FALSE;
5792         }
5793
5794         if (!param_klass->valuetype) {
5795                 if (cfg->verbose_level > 3)
5796                         printf ("[UNSAFE-MOV-INTRISIC]\targs are reference types\n");
5797                 return TRUE;
5798         }
5799
5800         //That are blitable
5801         if (param_klass->has_references || return_klass->has_references)
5802                 return FALSE;
5803
5804         /* Avoid mixing structs and primitive types/enums, they need to be handled differently in the JIT */
5805         if ((MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && !MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)) ||
5806                 (!MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && MONO_TYPE_ISSTRUCT (&return_klass->byval_arg))) {
5807                         if (cfg->verbose_level > 3)
5808                                 printf ("[UNSAFE-MOV-INTRISIC]\tmixing structs and scalars\n");
5809                 return FALSE;
5810         }
5811
5812         if (param_klass->byval_arg.type == MONO_TYPE_R4 || param_klass->byval_arg.type == MONO_TYPE_R8 ||
5813                 return_klass->byval_arg.type == MONO_TYPE_R4 || return_klass->byval_arg.type == MONO_TYPE_R8) {
5814                 if (cfg->verbose_level > 3)
5815                         printf ("[UNSAFE-MOV-INTRISIC]\tfloat or double are not supported\n");
5816                 return FALSE;
5817         }
5818
5819         param_size = mono_class_value_size (param_klass, &align);
5820         return_size = mono_class_value_size (return_klass, &align);
5821
5822         //We can do it if sizes match
5823         if (param_size == return_size) {
5824                 if (cfg->verbose_level > 3)
5825                         printf ("[UNSAFE-MOV-INTRISIC]\tsame size\n");
5826                 return TRUE;
5827         }
5828
5829         //No simple way to handle struct if sizes don't match
5830         if (MONO_TYPE_ISSTRUCT (&param_klass->byval_arg)) {
5831                 if (cfg->verbose_level > 3)
5832                         printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch and type is a struct\n");
5833                 return FALSE;
5834         }
5835
5836         /*
5837          * Same reg size category.
5838          * A quick note on why we don't require widening here.
5839          * The intrinsic is "R Array.UnsafeMov<S,R> (S s)".
5840          *
5841          * Since the source value comes from a function argument, the JIT will already have
5842          * the value in a VREG and performed any widening needed before (say, when loading from a field).
5843          */
5844         if (param_size <= 4 && return_size <= 4) {
5845                 if (cfg->verbose_level > 3)
5846                         printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch but both are of the same reg class\n");
5847                 return TRUE;
5848         }
5849
5850         return FALSE;
5851 }
5852
5853 static MonoInst*
5854 emit_array_unsafe_mov (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args)
5855 {
5856         MonoClass *param_klass = mono_class_from_mono_type (fsig->params [0]);
5857         MonoClass *return_klass = mono_class_from_mono_type (fsig->ret);
5858
5859         if (mini_is_gsharedvt_variable_type (fsig->ret))
5860                 return NULL;
5861
5862         //Valuetypes that are semantically equivalent or numbers than can be widened to
5863         if (is_unsafe_mov_compatible (cfg, param_klass, return_klass))
5864                 return args [0];
5865
5866         //Arrays of valuetypes that are semantically equivalent
5867         if (param_klass->rank == 1 && return_klass->rank == 1 && is_unsafe_mov_compatible (cfg, param_klass->element_class, return_klass->element_class))
5868                 return args [0];
5869
5870         return NULL;
5871 }
5872
5873 static MonoInst*
5874 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5875 {
5876 #ifdef MONO_ARCH_SIMD_INTRINSICS
5877         MonoInst *ins = NULL;
5878
5879         if (cfg->opt & MONO_OPT_SIMD) {
5880                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5881                 if (ins)
5882                         return ins;
5883         }
5884 #endif
5885
5886         return mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5887 }
5888
5889 static MonoInst*
5890 emit_memory_barrier (MonoCompile *cfg, int kind)
5891 {
5892         MonoInst *ins = NULL;
5893         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
5894         MONO_ADD_INS (cfg->cbb, ins);
5895         ins->backend.memory_barrier_kind = kind;
5896
5897         return ins;
5898 }
5899
5900 static MonoInst*
5901 llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5902 {
5903         MonoInst *ins = NULL;
5904         int opcode = 0;
5905
5906         /* The LLVM backend supports these intrinsics */
5907         if (cmethod->klass == mono_defaults.math_class) {
5908                 if (strcmp (cmethod->name, "Sin") == 0) {
5909                         opcode = OP_SIN;
5910                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5911                         opcode = OP_COS;
5912                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
5913                         opcode = OP_SQRT;
5914                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5915                         opcode = OP_ABS;
5916                 }
5917
5918                 if (opcode && fsig->param_count == 1) {
5919                         MONO_INST_NEW (cfg, ins, opcode);
5920                         ins->type = STACK_R8;
5921                         ins->dreg = mono_alloc_dreg (cfg, ins->type);
5922                         ins->sreg1 = args [0]->dreg;
5923                         MONO_ADD_INS (cfg->cbb, ins);
5924                 }
5925
5926                 opcode = 0;
5927                 if (cfg->opt & MONO_OPT_CMOV) {
5928                         if (strcmp (cmethod->name, "Min") == 0) {
5929                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5930                                         opcode = OP_IMIN;
5931                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5932                                         opcode = OP_IMIN_UN;
5933                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5934                                         opcode = OP_LMIN;
5935                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5936                                         opcode = OP_LMIN_UN;
5937                         } else if (strcmp (cmethod->name, "Max") == 0) {
5938                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5939                                         opcode = OP_IMAX;
5940                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5941                                         opcode = OP_IMAX_UN;
5942                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5943                                         opcode = OP_LMAX;
5944                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5945                                         opcode = OP_LMAX_UN;
5946                         }
5947                 }
5948
5949                 if (opcode && fsig->param_count == 2) {
5950                         MONO_INST_NEW (cfg, ins, opcode);
5951                         ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
5952                         ins->dreg = mono_alloc_dreg (cfg, ins->type);
5953                         ins->sreg1 = args [0]->dreg;
5954                         ins->sreg2 = args [1]->dreg;
5955                         MONO_ADD_INS (cfg->cbb, ins);
5956                 }
5957         }
5958
5959         return ins;
5960 }
5961
5962 static MonoInst*
5963 mini_emit_inst_for_sharable_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5964 {
5965         if (cmethod->klass == mono_defaults.array_class) {
5966                 if (strcmp (cmethod->name, "UnsafeStore") == 0)
5967                         return emit_array_unsafe_access (cfg, fsig, args, TRUE);
5968                 else if (strcmp (cmethod->name, "UnsafeLoad") == 0)
5969                         return emit_array_unsafe_access (cfg, fsig, args, FALSE);
5970                 else if (strcmp (cmethod->name, "UnsafeMov") == 0)
5971                         return emit_array_unsafe_mov (cfg, fsig, args);
5972         }
5973
5974         return NULL;
5975 }
5976
5977 static MonoInst*
5978 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5979 {
5980         MonoInst *ins = NULL;
5981
5982          MonoClass *runtime_helpers_class = mono_class_get_runtime_helpers_class ();
5983
5984         if (cmethod->klass == mono_defaults.string_class) {
5985                 if (strcmp (cmethod->name, "get_Chars") == 0 && fsig->param_count + fsig->hasthis == 2) {
5986                         int dreg = alloc_ireg (cfg);
5987                         int index_reg = alloc_preg (cfg);
5988                         int add_reg = alloc_preg (cfg);
5989
5990 #if SIZEOF_REGISTER == 8
5991                         if (COMPILE_LLVM (cfg)) {
5992                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, args [1]->dreg);
5993                         } else {
5994                                 /* The array reg is 64 bits but the index reg is only 32 */
5995                                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
5996                         }
5997 #else
5998                         index_reg = args [1]->dreg;
5999 #endif  
6000                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
6001
6002 #if defined(TARGET_X86) || defined(TARGET_AMD64)
6003                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, MONO_STRUCT_OFFSET (MonoString, chars));
6004                         add_reg = ins->dreg;
6005                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
6006                                                                    add_reg, 0);
6007 #else
6008                         int mult_reg = alloc_preg (cfg);
6009                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
6010                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
6011                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
6012                                                                    add_reg, MONO_STRUCT_OFFSET (MonoString, chars));
6013 #endif
6014                         type_from_op (cfg, ins, NULL, NULL);
6015                         return ins;
6016                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
6017                         int dreg = alloc_ireg (cfg);
6018                         /* Decompose later to allow more optimizations */
6019                         EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
6020                         ins->type = STACK_I4;
6021                         ins->flags |= MONO_INST_FAULT;
6022                         cfg->cbb->has_array_access = TRUE;
6023                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
6024
6025                         return ins;
6026                 } else 
6027                         return NULL;
6028         } else if (cmethod->klass == mono_defaults.object_class) {
6029                 if (strcmp (cmethod->name, "GetType") == 0 && fsig->param_count + fsig->hasthis == 1) {
6030                         int dreg = alloc_ireg_ref (cfg);
6031                         int vt_reg = alloc_preg (cfg);
6032                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
6033                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, MONO_STRUCT_OFFSET (MonoVTable, type));
6034                         type_from_op (cfg, ins, NULL, NULL);
6035
6036                         return ins;
6037                 } else if (!cfg->backend->emulate_mul_div && strcmp (cmethod->name, "InternalGetHashCode") == 0 && fsig->param_count == 1 && !mono_gc_is_moving ()) {
6038                         int dreg = alloc_ireg (cfg);
6039                         int t1 = alloc_ireg (cfg);
6040         
6041                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
6042                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
6043                         ins->type = STACK_I4;
6044
6045                         return ins;
6046                 } else if (strcmp (cmethod->name, ".ctor") == 0 && fsig->param_count == 0) {
6047                         MONO_INST_NEW (cfg, ins, OP_NOP);
6048                         MONO_ADD_INS (cfg->cbb, ins);
6049                         return ins;
6050                 } else
6051                         return NULL;
6052         } else if (cmethod->klass == mono_defaults.array_class) {
6053                 if (strcmp (cmethod->name, "GetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
6054                         return emit_array_generic_access (cfg, fsig, args, FALSE);
6055                 else if (strcmp (cmethod->name, "SetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
6056                         return emit_array_generic_access (cfg, fsig, args, TRUE);
6057
6058 #ifndef MONO_BIG_ARRAYS
6059                 /*
6060                  * This is an inline version of GetLength/GetLowerBound(0) used frequently in
6061                  * Array methods.
6062                  */
6063                 else if (((strcmp (cmethod->name, "GetLength") == 0 && fsig->param_count + fsig->hasthis == 2) ||
6064                          (strcmp (cmethod->name, "GetLowerBound") == 0 && fsig->param_count + fsig->hasthis == 2)) &&
6065                          args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) {
6066                         int dreg = alloc_ireg (cfg);
6067                         int bounds_reg = alloc_ireg_mp (cfg);
6068                         MonoBasicBlock *end_bb, *szarray_bb;
6069                         gboolean get_length = strcmp (cmethod->name, "GetLength") == 0;
6070
6071                         NEW_BBLOCK (cfg, end_bb);
6072                         NEW_BBLOCK (cfg, szarray_bb);
6073
6074                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOAD_MEMBASE, bounds_reg,
6075                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
6076                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
6077                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, szarray_bb);
6078                         /* Non-szarray case */
6079                         if (get_length)
6080                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
6081                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
6082                         else
6083                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
6084                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
6085                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
6086                         MONO_START_BB (cfg, szarray_bb);
6087                         /* Szarray case */
6088                         if (get_length)
6089                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
6090                                                                            args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
6091                         else
6092                                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
6093                         MONO_START_BB (cfg, end_bb);
6094
6095                         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg);
6096                         ins->type = STACK_I4;
6097                         
6098                         return ins;
6099                 }
6100 #endif
6101
6102                 if (cmethod->name [0] != 'g')
6103                         return NULL;
6104
6105                 if (strcmp (cmethod->name, "get_Rank") == 0 && fsig->param_count + fsig->hasthis == 1) {
6106                         int dreg = alloc_ireg (cfg);
6107                         int vtable_reg = alloc_preg (cfg);
6108                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
6109                                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
6110                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
6111                                                                    vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
6112                         type_from_op (cfg, ins, NULL, NULL);
6113
6114                         return ins;
6115                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
6116                         int dreg = alloc_ireg (cfg);
6117
6118                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
6119                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
6120                         type_from_op (cfg, ins, NULL, NULL);
6121
6122                         return ins;
6123                 } else
6124                         return NULL;
6125         } else if (cmethod->klass == runtime_helpers_class) {
6126                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0 && fsig->param_count == 0) {
6127                         EMIT_NEW_ICONST (cfg, ins, MONO_STRUCT_OFFSET (MonoString, chars));
6128                         return ins;
6129                 } else
6130                         return NULL;
6131         } else if (cmethod->klass == mono_defaults.monitor_class) {
6132                 gboolean is_enter = FALSE;
6133                 gboolean is_v4 = FALSE;
6134
6135                 if (!strcmp (cmethod->name, "Enter") && fsig->param_count == 2 && fsig->params [1]->byref) {
6136                         is_enter = TRUE;
6137                         is_v4 = TRUE;
6138                 }
6139                 if (!strcmp (cmethod->name, "Enter") && fsig->param_count == 1)
6140                         is_enter = TRUE;
6141
6142                 if (is_enter) {
6143                         /*
6144                          * To make async stack traces work, icalls which can block should have a wrapper.
6145                          * For Monitor.Enter, emit two calls: a fastpath which doesn't have a wrapper, and a slowpath, which does.
6146                          */
6147                         MonoBasicBlock *end_bb;
6148
6149                         NEW_BBLOCK (cfg, end_bb);
6150
6151                         ins = mono_emit_jit_icall (cfg, is_v4 ? (gpointer)mono_monitor_enter_v4_fast : (gpointer)mono_monitor_enter_fast, args);
6152                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, ins->dreg, 0);
6153                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, end_bb);
6154                         ins = mono_emit_jit_icall (cfg, is_v4 ? (gpointer)mono_monitor_enter_v4 : (gpointer)mono_monitor_enter, args);
6155                         MONO_START_BB (cfg, end_bb);
6156                         return ins;
6157                 }
6158         } else if (cmethod->klass == mono_defaults.thread_class) {
6159                 if (strcmp (cmethod->name, "SpinWait_nop") == 0 && fsig->param_count == 0) {
6160                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
6161                         MONO_ADD_INS (cfg->cbb, ins);
6162                         return ins;
6163                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0) {
6164                         return emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6165                 } else if (!strcmp (cmethod->name, "VolatileRead") && fsig->param_count == 1) {
6166                         guint32 opcode = 0;
6167                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6168
6169                         if (fsig->params [0]->type == MONO_TYPE_I1)
6170                                 opcode = OP_LOADI1_MEMBASE;
6171                         else if (fsig->params [0]->type == MONO_TYPE_U1)
6172                                 opcode = OP_LOADU1_MEMBASE;
6173                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6174                                 opcode = OP_LOADI2_MEMBASE;
6175                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6176                                 opcode = OP_LOADU2_MEMBASE;
6177                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6178                                 opcode = OP_LOADI4_MEMBASE;
6179                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6180                                 opcode = OP_LOADU4_MEMBASE;
6181                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
6182                                 opcode = OP_LOADI8_MEMBASE;
6183                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6184                                 opcode = OP_LOADR4_MEMBASE;
6185                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6186                                 opcode = OP_LOADR8_MEMBASE;
6187                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
6188                                 opcode = OP_LOAD_MEMBASE;
6189
6190                         if (opcode) {
6191                                 MONO_INST_NEW (cfg, ins, opcode);
6192                                 ins->inst_basereg = args [0]->dreg;
6193                                 ins->inst_offset = 0;
6194                                 MONO_ADD_INS (cfg->cbb, ins);
6195
6196                                 switch (fsig->params [0]->type) {
6197                                 case MONO_TYPE_I1:
6198                                 case MONO_TYPE_U1:
6199                                 case MONO_TYPE_I2:
6200                                 case MONO_TYPE_U2:
6201                                 case MONO_TYPE_I4:
6202                                 case MONO_TYPE_U4:
6203                                         ins->dreg = mono_alloc_ireg (cfg);
6204                                         ins->type = STACK_I4;
6205                                         break;
6206                                 case MONO_TYPE_I8:
6207                                 case MONO_TYPE_U8:
6208                                         ins->dreg = mono_alloc_lreg (cfg);
6209                                         ins->type = STACK_I8;
6210                                         break;
6211                                 case MONO_TYPE_I:
6212                                 case MONO_TYPE_U:
6213                                         ins->dreg = mono_alloc_ireg (cfg);
6214 #if SIZEOF_REGISTER == 8
6215                                         ins->type = STACK_I8;
6216 #else
6217                                         ins->type = STACK_I4;
6218 #endif
6219                                         break;
6220                                 case MONO_TYPE_R4:
6221                                 case MONO_TYPE_R8:
6222                                         ins->dreg = mono_alloc_freg (cfg);
6223                                         ins->type = STACK_R8;
6224                                         break;
6225                                 default:
6226                                         g_assert (mini_type_is_reference (fsig->params [0]));
6227                                         ins->dreg = mono_alloc_ireg_ref (cfg);
6228                                         ins->type = STACK_OBJ;
6229                                         break;
6230                                 }
6231
6232                                 if (opcode == OP_LOADI8_MEMBASE)
6233                                         ins = mono_decompose_opcode (cfg, ins);
6234
6235                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6236
6237                                 return ins;
6238                         }
6239                 } else if (!strcmp (cmethod->name, "VolatileWrite") && fsig->param_count == 2) {
6240                         guint32 opcode = 0;
6241                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6242
6243                         if (fsig->params [0]->type == MONO_TYPE_I1 || fsig->params [0]->type == MONO_TYPE_U1)
6244                                 opcode = OP_STOREI1_MEMBASE_REG;
6245                         else if (fsig->params [0]->type == MONO_TYPE_I2 || fsig->params [0]->type == MONO_TYPE_U2)
6246                                 opcode = OP_STOREI2_MEMBASE_REG;
6247                         else if (fsig->params [0]->type == MONO_TYPE_I4 || fsig->params [0]->type == MONO_TYPE_U4)
6248                                 opcode = OP_STOREI4_MEMBASE_REG;
6249                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
6250                                 opcode = OP_STOREI8_MEMBASE_REG;
6251                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6252                                 opcode = OP_STORER4_MEMBASE_REG;
6253                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6254                                 opcode = OP_STORER8_MEMBASE_REG;
6255                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
6256                                 opcode = OP_STORE_MEMBASE_REG;
6257
6258                         if (opcode) {
6259                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6260
6261                                 MONO_INST_NEW (cfg, ins, opcode);
6262                                 ins->sreg1 = args [1]->dreg;
6263                                 ins->inst_destbasereg = args [0]->dreg;
6264                                 ins->inst_offset = 0;
6265                                 MONO_ADD_INS (cfg->cbb, ins);
6266
6267                                 if (opcode == OP_STOREI8_MEMBASE_REG)
6268                                         ins = mono_decompose_opcode (cfg, ins);
6269
6270                                 return ins;
6271                         }
6272                 }
6273         } else if (cmethod->klass->image == mono_defaults.corlib &&
6274                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6275                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
6276                 ins = NULL;
6277
6278 #if SIZEOF_REGISTER == 8
6279                 if (!cfg->llvm_only && strcmp (cmethod->name, "Read") == 0 && fsig->param_count == 1 && (fsig->params [0]->type == MONO_TYPE_I8)) {
6280                         if (!cfg->llvm_only && mono_arch_opcode_supported (OP_ATOMIC_LOAD_I8)) {
6281                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_LOAD_I8);
6282                                 ins->dreg = mono_alloc_preg (cfg);
6283                                 ins->sreg1 = args [0]->dreg;
6284                                 ins->type = STACK_I8;
6285                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_SEQ;
6286                                 MONO_ADD_INS (cfg->cbb, ins);
6287                         } else {
6288                                 MonoInst *load_ins;
6289
6290                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6291
6292                                 /* 64 bit reads are already atomic */
6293                                 MONO_INST_NEW (cfg, load_ins, OP_LOADI8_MEMBASE);
6294                                 load_ins->dreg = mono_alloc_preg (cfg);
6295                                 load_ins->inst_basereg = args [0]->dreg;
6296                                 load_ins->inst_offset = 0;
6297                                 load_ins->type = STACK_I8;
6298                                 MONO_ADD_INS (cfg->cbb, load_ins);
6299
6300                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6301
6302                                 ins = load_ins;
6303                         }
6304                 }
6305 #endif
6306
6307                 if (strcmp (cmethod->name, "Increment") == 0 && fsig->param_count == 1) {
6308                         MonoInst *ins_iconst;
6309                         guint32 opcode = 0;
6310
6311                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6312                                 opcode = OP_ATOMIC_ADD_I4;
6313                                 cfg->has_atomic_add_i4 = TRUE;
6314                         }
6315 #if SIZEOF_REGISTER == 8
6316                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6317                                 opcode = OP_ATOMIC_ADD_I8;
6318 #endif
6319                         if (opcode) {
6320                                 if (!mono_arch_opcode_supported (opcode))
6321                                         return NULL;
6322                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6323                                 ins_iconst->inst_c0 = 1;
6324                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6325                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6326
6327                                 MONO_INST_NEW (cfg, ins, opcode);
6328                                 ins->dreg = mono_alloc_ireg (cfg);
6329                                 ins->inst_basereg = args [0]->dreg;
6330                                 ins->inst_offset = 0;
6331                                 ins->sreg2 = ins_iconst->dreg;
6332                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6333                                 MONO_ADD_INS (cfg->cbb, ins);
6334                         }
6335                 } else if (strcmp (cmethod->name, "Decrement") == 0 && fsig->param_count == 1) {
6336                         MonoInst *ins_iconst;
6337                         guint32 opcode = 0;
6338
6339                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6340                                 opcode = OP_ATOMIC_ADD_I4;
6341                                 cfg->has_atomic_add_i4 = TRUE;
6342                         }
6343 #if SIZEOF_REGISTER == 8
6344                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6345                                 opcode = OP_ATOMIC_ADD_I8;
6346 #endif
6347                         if (opcode) {
6348                                 if (!mono_arch_opcode_supported (opcode))
6349                                         return NULL;
6350                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6351                                 ins_iconst->inst_c0 = -1;
6352                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6353                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6354
6355                                 MONO_INST_NEW (cfg, ins, opcode);
6356                                 ins->dreg = mono_alloc_ireg (cfg);
6357                                 ins->inst_basereg = args [0]->dreg;
6358                                 ins->inst_offset = 0;
6359                                 ins->sreg2 = ins_iconst->dreg;
6360                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6361                                 MONO_ADD_INS (cfg->cbb, ins);
6362                         }
6363                 } else if (strcmp (cmethod->name, "Add") == 0 && fsig->param_count == 2) {
6364                         guint32 opcode = 0;
6365
6366                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6367                                 opcode = OP_ATOMIC_ADD_I4;
6368                                 cfg->has_atomic_add_i4 = TRUE;
6369                         }
6370 #if SIZEOF_REGISTER == 8
6371                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6372                                 opcode = OP_ATOMIC_ADD_I8;
6373 #endif
6374                         if (opcode) {
6375                                 if (!mono_arch_opcode_supported (opcode))
6376                                         return NULL;
6377                                 MONO_INST_NEW (cfg, ins, opcode);
6378                                 ins->dreg = mono_alloc_ireg (cfg);
6379                                 ins->inst_basereg = args [0]->dreg;
6380                                 ins->inst_offset = 0;
6381                                 ins->sreg2 = args [1]->dreg;
6382                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6383                                 MONO_ADD_INS (cfg->cbb, ins);
6384                         }
6385                 }
6386                 else if (strcmp (cmethod->name, "Exchange") == 0 && fsig->param_count == 2) {
6387                         MonoInst *f2i = NULL, *i2f;
6388                         guint32 opcode, f2i_opcode, i2f_opcode;
6389                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6390                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
6391
6392                         if (fsig->params [0]->type == MONO_TYPE_I4 ||
6393                             fsig->params [0]->type == MONO_TYPE_R4) {
6394                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6395                                 f2i_opcode = OP_MOVE_F_TO_I4;
6396                                 i2f_opcode = OP_MOVE_I4_TO_F;
6397                                 cfg->has_atomic_exchange_i4 = TRUE;
6398                         }
6399 #if SIZEOF_REGISTER == 8
6400                         else if (is_ref ||
6401                                  fsig->params [0]->type == MONO_TYPE_I8 ||
6402                                  fsig->params [0]->type == MONO_TYPE_R8 ||
6403                                  fsig->params [0]->type == MONO_TYPE_I) {
6404                                 opcode = OP_ATOMIC_EXCHANGE_I8;
6405                                 f2i_opcode = OP_MOVE_F_TO_I8;
6406                                 i2f_opcode = OP_MOVE_I8_TO_F;
6407                         }
6408 #else
6409                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I) {
6410                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6411                                 cfg->has_atomic_exchange_i4 = TRUE;
6412                         }
6413 #endif
6414                         else
6415                                 return NULL;
6416
6417                         if (!mono_arch_opcode_supported (opcode))
6418                                 return NULL;
6419
6420                         if (is_float) {
6421                                 /* TODO: Decompose these opcodes instead of bailing here. */
6422                                 if (COMPILE_SOFT_FLOAT (cfg))
6423                                         return NULL;
6424
6425                                 MONO_INST_NEW (cfg, f2i, f2i_opcode);
6426                                 f2i->dreg = mono_alloc_ireg (cfg);
6427                                 f2i->sreg1 = args [1]->dreg;
6428                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6429                                         f2i->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6430                                 MONO_ADD_INS (cfg->cbb, f2i);
6431                         }
6432
6433                         MONO_INST_NEW (cfg, ins, opcode);
6434                         ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg);
6435                         ins->inst_basereg = args [0]->dreg;
6436                         ins->inst_offset = 0;
6437                         ins->sreg2 = is_float ? f2i->dreg : args [1]->dreg;
6438                         MONO_ADD_INS (cfg->cbb, ins);
6439
6440                         switch (fsig->params [0]->type) {
6441                         case MONO_TYPE_I4:
6442                                 ins->type = STACK_I4;
6443                                 break;
6444                         case MONO_TYPE_I8:
6445                                 ins->type = STACK_I8;
6446                                 break;
6447                         case MONO_TYPE_I:
6448 #if SIZEOF_REGISTER == 8
6449                                 ins->type = STACK_I8;
6450 #else
6451                                 ins->type = STACK_I4;
6452 #endif
6453                                 break;
6454                         case MONO_TYPE_R4:
6455                         case MONO_TYPE_R8:
6456                                 ins->type = STACK_R8;
6457                                 break;
6458                         default:
6459                                 g_assert (mini_type_is_reference (fsig->params [0]));
6460                                 ins->type = STACK_OBJ;
6461                                 break;
6462                         }
6463
6464                         if (is_float) {
6465                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6466                                 i2f->dreg = mono_alloc_freg (cfg);
6467                                 i2f->sreg1 = ins->dreg;
6468                                 i2f->type = STACK_R8;
6469                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6470                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6471                                 MONO_ADD_INS (cfg->cbb, i2f);
6472
6473                                 ins = i2f;
6474                         }
6475
6476                         if (cfg->gen_write_barriers && is_ref)
6477                                 emit_write_barrier (cfg, args [0], args [1]);
6478                 }
6479                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 3) {
6480                         MonoInst *f2i_new = NULL, *f2i_cmp = NULL, *i2f;
6481                         guint32 opcode, f2i_opcode, i2f_opcode;
6482                         gboolean is_ref = mini_type_is_reference (fsig->params [1]);
6483                         gboolean is_float = fsig->params [1]->type == MONO_TYPE_R4 || fsig->params [1]->type == MONO_TYPE_R8;
6484
6485                         if (fsig->params [1]->type == MONO_TYPE_I4 ||
6486                             fsig->params [1]->type == MONO_TYPE_R4) {
6487                                 opcode = OP_ATOMIC_CAS_I4;
6488                                 f2i_opcode = OP_MOVE_F_TO_I4;
6489                                 i2f_opcode = OP_MOVE_I4_TO_F;
6490                                 cfg->has_atomic_cas_i4 = TRUE;
6491                         }
6492 #if SIZEOF_REGISTER == 8
6493                         else if (is_ref ||
6494                                  fsig->params [1]->type == MONO_TYPE_I8 ||
6495                                  fsig->params [1]->type == MONO_TYPE_R8 ||
6496                                  fsig->params [1]->type == MONO_TYPE_I) {
6497                                 opcode = OP_ATOMIC_CAS_I8;
6498                                 f2i_opcode = OP_MOVE_F_TO_I8;
6499                                 i2f_opcode = OP_MOVE_I8_TO_F;
6500                         }
6501 #else
6502                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I) {
6503                                 opcode = OP_ATOMIC_CAS_I4;
6504                                 cfg->has_atomic_cas_i4 = TRUE;
6505                         }
6506 #endif
6507                         else
6508                                 return NULL;
6509
6510                         if (!mono_arch_opcode_supported (opcode))
6511                                 return NULL;
6512
6513                         if (is_float) {
6514                                 /* TODO: Decompose these opcodes instead of bailing here. */
6515                                 if (COMPILE_SOFT_FLOAT (cfg))
6516                                         return NULL;
6517
6518                                 MONO_INST_NEW (cfg, f2i_new, f2i_opcode);
6519                                 f2i_new->dreg = mono_alloc_ireg (cfg);
6520                                 f2i_new->sreg1 = args [1]->dreg;
6521                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6522                                         f2i_new->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6523                                 MONO_ADD_INS (cfg->cbb, f2i_new);
6524
6525                                 MONO_INST_NEW (cfg, f2i_cmp, f2i_opcode);
6526                                 f2i_cmp->dreg = mono_alloc_ireg (cfg);
6527                                 f2i_cmp->sreg1 = args [2]->dreg;
6528                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6529                                         f2i_cmp->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6530                                 MONO_ADD_INS (cfg->cbb, f2i_cmp);
6531                         }
6532
6533                         MONO_INST_NEW (cfg, ins, opcode);
6534                         ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
6535                         ins->sreg1 = args [0]->dreg;
6536                         ins->sreg2 = is_float ? f2i_new->dreg : args [1]->dreg;
6537                         ins->sreg3 = is_float ? f2i_cmp->dreg : args [2]->dreg;
6538                         MONO_ADD_INS (cfg->cbb, ins);
6539
6540                         switch (fsig->params [1]->type) {
6541                         case MONO_TYPE_I4:
6542                                 ins->type = STACK_I4;
6543                                 break;
6544                         case MONO_TYPE_I8:
6545                                 ins->type = STACK_I8;
6546                                 break;
6547                         case MONO_TYPE_I:
6548 #if SIZEOF_REGISTER == 8
6549                                 ins->type = STACK_I8;
6550 #else
6551                                 ins->type = STACK_I4;
6552 #endif
6553                                 break;
6554                         case MONO_TYPE_R4:
6555                                 ins->type = cfg->r4_stack_type;
6556                                 break;
6557                         case MONO_TYPE_R8:
6558                                 ins->type = STACK_R8;
6559                                 break;
6560                         default:
6561                                 g_assert (mini_type_is_reference (fsig->params [1]));
6562                                 ins->type = STACK_OBJ;
6563                                 break;
6564                         }
6565
6566                         if (is_float) {
6567                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6568                                 i2f->dreg = mono_alloc_freg (cfg);
6569                                 i2f->sreg1 = ins->dreg;
6570                                 i2f->type = STACK_R8;
6571                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6572                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6573                                 MONO_ADD_INS (cfg->cbb, i2f);
6574
6575                                 ins = i2f;
6576                         }
6577
6578                         if (cfg->gen_write_barriers && is_ref)
6579                                 emit_write_barrier (cfg, args [0], args [1]);
6580                 }
6581                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 4 &&
6582                          fsig->params [1]->type == MONO_TYPE_I4) {
6583                         MonoInst *cmp, *ceq;
6584
6585                         if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I4))
6586                                 return NULL;
6587
6588                         /* int32 r = CAS (location, value, comparand); */
6589                         MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
6590                         ins->dreg = alloc_ireg (cfg);
6591                         ins->sreg1 = args [0]->dreg;
6592                         ins->sreg2 = args [1]->dreg;
6593                         ins->sreg3 = args [2]->dreg;
6594                         ins->type = STACK_I4;
6595                         MONO_ADD_INS (cfg->cbb, ins);
6596
6597                         /* bool result = r == comparand; */
6598                         MONO_INST_NEW (cfg, cmp, OP_ICOMPARE);
6599                         cmp->sreg1 = ins->dreg;
6600                         cmp->sreg2 = args [2]->dreg;
6601                         cmp->type = STACK_I4;
6602                         MONO_ADD_INS (cfg->cbb, cmp);
6603
6604                         MONO_INST_NEW (cfg, ceq, OP_ICEQ);
6605                         ceq->dreg = alloc_ireg (cfg);
6606                         ceq->type = STACK_I4;
6607                         MONO_ADD_INS (cfg->cbb, ceq);
6608
6609                         /* *success = result; */
6610                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, args [3]->dreg, 0, ceq->dreg);
6611
6612                         cfg->has_atomic_cas_i4 = TRUE;
6613                 }
6614                 else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0)
6615                         ins = emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6616
6617                 if (ins)
6618                         return ins;
6619         } else if (cmethod->klass->image == mono_defaults.corlib &&
6620                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6621                            (strcmp (cmethod->klass->name, "Volatile") == 0)) {
6622                 ins = NULL;
6623
6624                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Read") && fsig->param_count == 1) {
6625                         guint32 opcode = 0;
6626                         MonoType *t = fsig->params [0];
6627                         gboolean is_ref;
6628                         gboolean is_float = t->type == MONO_TYPE_R4 || t->type == MONO_TYPE_R8;
6629
6630                         g_assert (t->byref);
6631                         /* t is a byref type, so the reference check is more complicated */
6632                         is_ref = mini_type_is_reference (&mono_class_from_mono_type (t)->byval_arg);
6633                         if (t->type == MONO_TYPE_I1)
6634                                 opcode = OP_ATOMIC_LOAD_I1;
6635                         else if (t->type == MONO_TYPE_U1 || t->type == MONO_TYPE_BOOLEAN)
6636                                 opcode = OP_ATOMIC_LOAD_U1;
6637                         else if (t->type == MONO_TYPE_I2)
6638                                 opcode = OP_ATOMIC_LOAD_I2;
6639                         else if (t->type == MONO_TYPE_U2)
6640                                 opcode = OP_ATOMIC_LOAD_U2;
6641                         else if (t->type == MONO_TYPE_I4)
6642                                 opcode = OP_ATOMIC_LOAD_I4;
6643                         else if (t->type == MONO_TYPE_U4)
6644                                 opcode = OP_ATOMIC_LOAD_U4;
6645                         else if (t->type == MONO_TYPE_R4)
6646                                 opcode = OP_ATOMIC_LOAD_R4;
6647                         else if (t->type == MONO_TYPE_R8)
6648                                 opcode = OP_ATOMIC_LOAD_R8;
6649 #if SIZEOF_REGISTER == 8
6650                         else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_I)
6651                                 opcode = OP_ATOMIC_LOAD_I8;
6652                         else if (is_ref || t->type == MONO_TYPE_U8 || t->type == MONO_TYPE_U)
6653                                 opcode = OP_ATOMIC_LOAD_U8;
6654 #else
6655                         else if (t->type == MONO_TYPE_I)
6656                                 opcode = OP_ATOMIC_LOAD_I4;
6657                         else if (is_ref || t->type == MONO_TYPE_U)
6658                                 opcode = OP_ATOMIC_LOAD_U4;
6659 #endif
6660
6661                         if (opcode) {
6662                                 if (!mono_arch_opcode_supported (opcode))
6663                                         return NULL;
6664
6665                                 MONO_INST_NEW (cfg, ins, opcode);
6666                                 ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : (is_float ? mono_alloc_freg (cfg) : mono_alloc_ireg (cfg));
6667                                 ins->sreg1 = args [0]->dreg;
6668                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_ACQ;
6669                                 MONO_ADD_INS (cfg->cbb, ins);
6670
6671                                 switch (t->type) {
6672                                 case MONO_TYPE_BOOLEAN:
6673                                 case MONO_TYPE_I1:
6674                                 case MONO_TYPE_U1:
6675                                 case MONO_TYPE_I2:
6676                                 case MONO_TYPE_U2:
6677                                 case MONO_TYPE_I4:
6678                                 case MONO_TYPE_U4:
6679                                         ins->type = STACK_I4;
6680                                         break;
6681                                 case MONO_TYPE_I8:
6682                                 case MONO_TYPE_U8:
6683                                         ins->type = STACK_I8;
6684                                         break;
6685                                 case MONO_TYPE_I:
6686                                 case MONO_TYPE_U:
6687 #if SIZEOF_REGISTER == 8
6688                                         ins->type = STACK_I8;
6689 #else
6690                                         ins->type = STACK_I4;
6691 #endif
6692                                         break;
6693                                 case MONO_TYPE_R4:
6694                                         ins->type = cfg->r4_stack_type;
6695                                         break;
6696                                 case MONO_TYPE_R8:
6697                                         ins->type = STACK_R8;
6698                                         break;
6699                                 default:
6700                                         g_assert (is_ref);
6701                                         ins->type = STACK_OBJ;
6702                                         break;
6703                                 }
6704                         }
6705                 }
6706
6707                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Write") && fsig->param_count == 2) {
6708                         guint32 opcode = 0;
6709                         MonoType *t = fsig->params [0];
6710                         gboolean is_ref;
6711
6712                         g_assert (t->byref);
6713                         is_ref = mini_type_is_reference (&mono_class_from_mono_type (t)->byval_arg);
6714                         if (t->type == MONO_TYPE_I1)
6715                                 opcode = OP_ATOMIC_STORE_I1;
6716                         else if (t->type == MONO_TYPE_U1 || t->type == MONO_TYPE_BOOLEAN)
6717                                 opcode = OP_ATOMIC_STORE_U1;
6718                         else if (t->type == MONO_TYPE_I2)
6719                                 opcode = OP_ATOMIC_STORE_I2;
6720                         else if (t->type == MONO_TYPE_U2)
6721                                 opcode = OP_ATOMIC_STORE_U2;
6722                         else if (t->type == MONO_TYPE_I4)
6723                                 opcode = OP_ATOMIC_STORE_I4;
6724                         else if (t->type == MONO_TYPE_U4)
6725                                 opcode = OP_ATOMIC_STORE_U4;
6726                         else if (t->type == MONO_TYPE_R4)
6727                                 opcode = OP_ATOMIC_STORE_R4;
6728                         else if (t->type == MONO_TYPE_R8)
6729                                 opcode = OP_ATOMIC_STORE_R8;
6730 #if SIZEOF_REGISTER == 8
6731                         else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_I)
6732                                 opcode = OP_ATOMIC_STORE_I8;
6733                         else if (is_ref || t->type == MONO_TYPE_U8 || t->type == MONO_TYPE_U)
6734                                 opcode = OP_ATOMIC_STORE_U8;
6735 #else
6736                         else if (t->type == MONO_TYPE_I)
6737                                 opcode = OP_ATOMIC_STORE_I4;
6738                         else if (is_ref || t->type == MONO_TYPE_U)
6739                                 opcode = OP_ATOMIC_STORE_U4;
6740 #endif
6741
6742                         if (opcode) {
6743                                 if (!mono_arch_opcode_supported (opcode))
6744                                         return NULL;
6745
6746                                 MONO_INST_NEW (cfg, ins, opcode);
6747                                 ins->dreg = args [0]->dreg;
6748                                 ins->sreg1 = args [1]->dreg;
6749                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_REL;
6750                                 MONO_ADD_INS (cfg->cbb, ins);
6751
6752                                 if (cfg->gen_write_barriers && is_ref)
6753                                         emit_write_barrier (cfg, args [0], args [1]);
6754                         }
6755                 }
6756
6757                 if (ins)
6758                         return ins;
6759         } else if (cmethod->klass->image == mono_defaults.corlib &&
6760                            (strcmp (cmethod->klass->name_space, "System.Diagnostics") == 0) &&
6761                            (strcmp (cmethod->klass->name, "Debugger") == 0)) {
6762                 if (!strcmp (cmethod->name, "Break") && fsig->param_count == 0) {
6763                         if (should_insert_brekpoint (cfg->method)) {
6764                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
6765                         } else {
6766                                 MONO_INST_NEW (cfg, ins, OP_NOP);
6767                                 MONO_ADD_INS (cfg->cbb, ins);
6768                         }
6769                         return ins;
6770                 }
6771         } else if (cmethod->klass->image == mono_defaults.corlib &&
6772                    (strcmp (cmethod->klass->name_space, "System") == 0) &&
6773                    (strcmp (cmethod->klass->name, "Environment") == 0)) {
6774                 if (!strcmp (cmethod->name, "get_IsRunningOnWindows") && fsig->param_count == 0) {
6775 #ifdef TARGET_WIN32
6776                         EMIT_NEW_ICONST (cfg, ins, 1);
6777 #else
6778                         EMIT_NEW_ICONST (cfg, ins, 0);
6779 #endif
6780                 }
6781         } else if (cmethod->klass->image == mono_defaults.corlib &&
6782                            (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
6783                            (strcmp (cmethod->klass->name, "Assembly") == 0)) {
6784                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetExecutingAssembly")) {
6785                         /* No stack walks are currently available, so implement this as an intrinsic */
6786                         MonoInst *assembly_ins;
6787
6788                         EMIT_NEW_AOTCONST (cfg, assembly_ins, MONO_PATCH_INFO_IMAGE, cfg->method->klass->image);
6789                         ins = mono_emit_jit_icall (cfg, mono_get_assembly_object, &assembly_ins);
6790                         return ins;
6791                 }
6792         } else if (cmethod->klass->image == mono_defaults.corlib &&
6793                            (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
6794                            (strcmp (cmethod->klass->name, "MethodBase") == 0)) {
6795                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetCurrentMethod")) {
6796                         /* No stack walks are currently available, so implement this as an intrinsic */
6797                         MonoInst *method_ins;
6798                         MonoMethod *declaring = cfg->method;
6799
6800                         /* This returns the declaring generic method */
6801                         if (declaring->is_inflated)
6802                                 declaring = ((MonoMethodInflated*)cfg->method)->declaring;
6803                         EMIT_NEW_AOTCONST (cfg, method_ins, MONO_PATCH_INFO_METHODCONST, declaring);
6804                         ins = mono_emit_jit_icall (cfg, mono_get_method_object, &method_ins);
6805                         cfg->no_inline = TRUE;
6806                         if (cfg->method != cfg->current_method)
6807                                 inline_failure (cfg, "MethodBase:GetCurrentMethod ()");
6808                         return ins;
6809                 }
6810         } else if (cmethod->klass == mono_defaults.math_class) {
6811                 /* 
6812                  * There is general branchless code for Min/Max, but it does not work for 
6813                  * all inputs:
6814                  * http://everything2.com/?node_id=1051618
6815                  */
6816         } else if (cmethod->klass == mono_defaults.systemtype_class && !strcmp (cmethod->name, "op_Equality")) {
6817                 EMIT_NEW_BIALU (cfg, ins, OP_COMPARE, -1, args [0]->dreg, args [1]->dreg);
6818                 MONO_INST_NEW (cfg, ins, OP_PCEQ);
6819                 ins->dreg = alloc_preg (cfg);
6820                 ins->type = STACK_I4;
6821                 MONO_ADD_INS (cfg->cbb, ins);
6822                 return ins;
6823         } else if (((!strcmp (cmethod->klass->image->assembly->aname.name, "MonoMac") ||
6824                     !strcmp (cmethod->klass->image->assembly->aname.name, "monotouch")) &&
6825                                 !strcmp (cmethod->klass->name_space, "XamCore.ObjCRuntime") &&
6826                                 !strcmp (cmethod->klass->name, "Selector")) ||
6827                            ((!strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.iOS") ||
6828                                  !strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.Mac")) &&
6829                                 !strcmp (cmethod->klass->name_space, "ObjCRuntime") &&
6830                                 !strcmp (cmethod->klass->name, "Selector"))
6831                            ) {
6832                 if ((cfg->backend->have_objc_get_selector || cfg->compile_llvm) &&
6833                         !strcmp (cmethod->name, "GetHandle") && fsig->param_count == 1 &&
6834                     (args [0]->opcode == OP_GOT_ENTRY || args [0]->opcode == OP_AOTCONST) &&
6835                     cfg->compile_aot) {
6836                         MonoInst *pi;
6837                         MonoJumpInfoToken *ji;
6838                         char *s;
6839
6840                         if (args [0]->opcode == OP_GOT_ENTRY) {
6841                                 pi = (MonoInst *)args [0]->inst_p1;
6842                                 g_assert (pi->opcode == OP_PATCH_INFO);
6843                                 g_assert (GPOINTER_TO_INT (pi->inst_p1) == MONO_PATCH_INFO_LDSTR);
6844                                 ji = (MonoJumpInfoToken *)pi->inst_p0;
6845                         } else {
6846                                 g_assert (GPOINTER_TO_INT (args [0]->inst_p1) == MONO_PATCH_INFO_LDSTR);
6847                                 ji = (MonoJumpInfoToken *)args [0]->inst_p0;
6848                         }
6849
6850                         NULLIFY_INS (args [0]);
6851
6852                         s = mono_ldstr_utf8 (ji->image, mono_metadata_token_index (ji->token), &cfg->error);
6853                         return_val_if_nok (&cfg->error, NULL);
6854
6855                         MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
6856                         ins->dreg = mono_alloc_ireg (cfg);
6857                         // FIXME: Leaks
6858                         ins->inst_p0 = s;
6859                         MONO_ADD_INS (cfg->cbb, ins);
6860                         return ins;
6861                 }
6862         }
6863
6864 #ifdef MONO_ARCH_SIMD_INTRINSICS
6865         if (cfg->opt & MONO_OPT_SIMD) {
6866                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
6867                 if (ins)
6868                         return ins;
6869         }
6870 #endif
6871
6872         ins = mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
6873         if (ins)
6874                 return ins;
6875
6876         if (COMPILE_LLVM (cfg)) {
6877                 ins = llvm_emit_inst_for_method (cfg, cmethod, fsig, args);
6878                 if (ins)
6879                         return ins;
6880         }
6881
6882         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
6883 }
6884
6885 /*
6886  * This entry point could be used later for arbitrary method
6887  * redirection.
6888  */
6889 inline static MonoInst*
6890 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
6891                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this_ins)
6892 {
6893         if (method->klass == mono_defaults.string_class) {
6894                 /* managed string allocation support */
6895                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
6896                         MonoInst *iargs [2];
6897                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
6898                         MonoMethod *managed_alloc = NULL;
6899
6900                         g_assert (vtable); /*Should not fail since it System.String*/
6901 #ifndef MONO_CROSS_COMPILE
6902                         managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE, FALSE);
6903 #endif
6904                         if (!managed_alloc)
6905                                 return NULL;
6906                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
6907                         iargs [1] = args [0];
6908                         return mono_emit_method_call (cfg, managed_alloc, iargs, this_ins);
6909                 }
6910         }
6911         return NULL;
6912 }
6913
6914 static void
6915 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
6916 {
6917         MonoInst *store, *temp;
6918         int i;
6919
6920         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
6921                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
6922
6923                 /*
6924                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
6925                  * would be different than the MonoInst's used to represent arguments, and
6926                  * the ldelema implementation can't deal with that.
6927                  * Solution: When ldelema is used on an inline argument, create a var for 
6928                  * it, emit ldelema on that var, and emit the saving code below in
6929                  * inline_method () if needed.
6930                  */
6931                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
6932                 cfg->args [i] = temp;
6933                 /* This uses cfg->args [i] which is set by the preceeding line */
6934                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
6935                 store->cil_code = sp [0]->cil_code;
6936                 sp++;
6937         }
6938 }
6939
6940 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
6941 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
6942
6943 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6944 static gboolean
6945 check_inline_called_method_name_limit (MonoMethod *called_method)
6946 {
6947         int strncmp_result;
6948         static const char *limit = NULL;
6949         
6950         if (limit == NULL) {
6951                 const char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
6952
6953                 if (limit_string != NULL)
6954                         limit = limit_string;
6955                 else
6956                         limit = "";
6957         }
6958
6959         if (limit [0] != '\0') {
6960                 char *called_method_name = mono_method_full_name (called_method, TRUE);
6961
6962                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
6963                 g_free (called_method_name);
6964         
6965                 //return (strncmp_result <= 0);
6966                 return (strncmp_result == 0);
6967         } else {
6968                 return TRUE;
6969         }
6970 }
6971 #endif
6972
6973 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6974 static gboolean
6975 check_inline_caller_method_name_limit (MonoMethod *caller_method)
6976 {
6977         int strncmp_result;
6978         static const char *limit = NULL;
6979         
6980         if (limit == NULL) {
6981                 const char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
6982                 if (limit_string != NULL) {
6983                         limit = limit_string;
6984                 } else {
6985                         limit = "";
6986                 }
6987         }
6988
6989         if (limit [0] != '\0') {
6990                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
6991
6992                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
6993                 g_free (caller_method_name);
6994         
6995                 //return (strncmp_result <= 0);
6996                 return (strncmp_result == 0);
6997         } else {
6998                 return TRUE;
6999         }
7000 }
7001 #endif
7002
7003 static void
7004 emit_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
7005 {
7006         static double r8_0 = 0.0;
7007         static float r4_0 = 0.0;
7008         MonoInst *ins;
7009         int t;
7010
7011         rtype = mini_get_underlying_type (rtype);
7012         t = rtype->type;
7013
7014         if (rtype->byref) {
7015                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
7016         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
7017                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
7018         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
7019                 MONO_EMIT_NEW_I8CONST (cfg, dreg, 0);
7020         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
7021                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
7022                 ins->type = STACK_R4;
7023                 ins->inst_p0 = (void*)&r4_0;
7024                 ins->dreg = dreg;
7025                 MONO_ADD_INS (cfg->cbb, ins);
7026         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
7027                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
7028                 ins->type = STACK_R8;
7029                 ins->inst_p0 = (void*)&r8_0;
7030                 ins->dreg = dreg;
7031                 MONO_ADD_INS (cfg->cbb, ins);
7032         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
7033                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
7034                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
7035         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
7036                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
7037         } else {
7038                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
7039         }
7040 }
7041
7042 static void
7043 emit_dummy_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
7044 {
7045         int t;
7046
7047         rtype = mini_get_underlying_type (rtype);
7048         t = rtype->type;
7049
7050         if (rtype->byref) {
7051                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_PCONST);
7052         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
7053                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_ICONST);
7054         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
7055                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_I8CONST);
7056         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
7057                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R4CONST);
7058         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
7059                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R8CONST);
7060         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
7061                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
7062                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
7063         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
7064                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
7065         } else {
7066                 emit_init_rvar (cfg, dreg, rtype);
7067         }
7068 }
7069
7070 /* If INIT is FALSE, emit dummy initialization statements to keep the IR valid */
7071 static void
7072 emit_init_local (MonoCompile *cfg, int local, MonoType *type, gboolean init)
7073 {
7074         MonoInst *var = cfg->locals [local];
7075         if (COMPILE_SOFT_FLOAT (cfg)) {
7076                 MonoInst *store;
7077                 int reg = alloc_dreg (cfg, (MonoStackType)var->type);
7078                 emit_init_rvar (cfg, reg, type);
7079                 EMIT_NEW_LOCSTORE (cfg, store, local, cfg->cbb->last_ins);
7080         } else {
7081                 if (init)
7082                         emit_init_rvar (cfg, var->dreg, type);
7083                 else
7084                         emit_dummy_init_rvar (cfg, var->dreg, type);
7085         }
7086 }
7087
7088 /*
7089  * inline_method:
7090  *
7091  * Return the cost of inlining CMETHOD, or zero if it should not be inlined.
7092  */
7093 static int
7094 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
7095                guchar *ip, guint real_offset, gboolean inline_always)
7096 {
7097         MonoError error;
7098         MonoInst *ins, *rvar = NULL;
7099         MonoMethodHeader *cheader;
7100         MonoBasicBlock *ebblock, *sbblock;
7101         int i, costs;
7102         MonoMethod *prev_inlined_method;
7103         MonoInst **prev_locals, **prev_args;
7104         MonoType **prev_arg_types;
7105         guint prev_real_offset;
7106         GHashTable *prev_cbb_hash;
7107         MonoBasicBlock **prev_cil_offset_to_bb;
7108         MonoBasicBlock *prev_cbb;
7109         const unsigned char *prev_ip;
7110         unsigned char *prev_cil_start;
7111         guint32 prev_cil_offset_to_bb_len;
7112         MonoMethod *prev_current_method;
7113         MonoGenericContext *prev_generic_context;
7114         gboolean ret_var_set, prev_ret_var_set, prev_disable_inline, virtual_ = FALSE;
7115
7116         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
7117
7118 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
7119         if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
7120                 return 0;
7121 #endif
7122 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
7123         if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
7124                 return 0;
7125 #endif
7126
7127         if (!fsig)
7128                 fsig = mono_method_signature (cmethod);
7129
7130         if (cfg->verbose_level > 2)
7131                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
7132
7133         if (!cmethod->inline_info) {
7134                 cfg->stat_inlineable_methods++;
7135                 cmethod->inline_info = 1;
7136         }
7137
7138         /* allocate local variables */
7139         cheader = mono_method_get_header_checked (cmethod, &error);
7140         if (!cheader) {
7141                 if (inline_always) {
7142                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
7143                         mono_error_move (&cfg->error, &error);
7144                 } else {
7145                         mono_error_cleanup (&error);
7146                 }
7147                 return 0;
7148         }
7149
7150         /*Must verify before creating locals as it can cause the JIT to assert.*/
7151         if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
7152                 mono_metadata_free_mh (cheader);
7153                 return 0;
7154         }
7155
7156         /* allocate space to store the return value */
7157         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
7158                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
7159         }
7160
7161         prev_locals = cfg->locals;
7162         cfg->locals = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));
7163         for (i = 0; i < cheader->num_locals; ++i)
7164                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
7165
7166         /* allocate start and end blocks */
7167         /* This is needed so if the inline is aborted, we can clean up */
7168         NEW_BBLOCK (cfg, sbblock);
7169         sbblock->real_offset = real_offset;
7170
7171         NEW_BBLOCK (cfg, ebblock);
7172         ebblock->block_num = cfg->num_bblocks++;
7173         ebblock->real_offset = real_offset;
7174
7175         prev_args = cfg->args;
7176         prev_arg_types = cfg->arg_types;
7177         prev_inlined_method = cfg->inlined_method;
7178         cfg->inlined_method = cmethod;
7179         cfg->ret_var_set = FALSE;
7180         cfg->inline_depth ++;
7181         prev_real_offset = cfg->real_offset;
7182         prev_cbb_hash = cfg->cbb_hash;
7183         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
7184         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
7185         prev_cil_start = cfg->cil_start;
7186         prev_ip = cfg->ip;
7187         prev_cbb = cfg->cbb;
7188         prev_current_method = cfg->current_method;
7189         prev_generic_context = cfg->generic_context;
7190         prev_ret_var_set = cfg->ret_var_set;
7191         prev_disable_inline = cfg->disable_inline;
7192
7193         if (ip && *ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
7194                 virtual_ = TRUE;
7195
7196         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, sp, real_offset, virtual_);
7197
7198         ret_var_set = cfg->ret_var_set;
7199
7200         cfg->inlined_method = prev_inlined_method;
7201         cfg->real_offset = prev_real_offset;
7202         cfg->cbb_hash = prev_cbb_hash;
7203         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
7204         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
7205         cfg->cil_start = prev_cil_start;
7206         cfg->ip = prev_ip;
7207         cfg->locals = prev_locals;
7208         cfg->args = prev_args;
7209         cfg->arg_types = prev_arg_types;
7210         cfg->current_method = prev_current_method;
7211         cfg->generic_context = prev_generic_context;
7212         cfg->ret_var_set = prev_ret_var_set;
7213         cfg->disable_inline = prev_disable_inline;
7214         cfg->inline_depth --;
7215
7216         if ((costs >= 0 && costs < 60) || inline_always || (costs >= 0 && (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))) {
7217                 if (cfg->verbose_level > 2)
7218                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
7219                 
7220                 cfg->stat_inlined_methods++;
7221
7222                 /* always add some code to avoid block split failures */
7223                 MONO_INST_NEW (cfg, ins, OP_NOP);
7224                 MONO_ADD_INS (prev_cbb, ins);
7225
7226                 prev_cbb->next_bb = sbblock;
7227                 link_bblock (cfg, prev_cbb, sbblock);
7228
7229                 /* 
7230                  * Get rid of the begin and end bblocks if possible to aid local
7231                  * optimizations.
7232                  */
7233                 mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
7234
7235                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
7236                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
7237
7238                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
7239                         MonoBasicBlock *prev = ebblock->in_bb [0];
7240
7241                         if (prev->next_bb == ebblock) {
7242                                 mono_merge_basic_blocks (cfg, prev, ebblock);
7243                                 cfg->cbb = prev;
7244                                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
7245                                         mono_merge_basic_blocks (cfg, prev_cbb, prev);
7246                                         cfg->cbb = prev_cbb;
7247                                 }
7248                         } else {
7249                                 /* There could be a bblock after 'prev', and making 'prev' the current bb could cause problems */
7250                                 cfg->cbb = ebblock;
7251                         }
7252                 } else {
7253                         /* 
7254                          * Its possible that the rvar is set in some prev bblock, but not in others.
7255                          * (#1835).
7256                          */
7257                         if (rvar) {
7258                                 MonoBasicBlock *bb;
7259
7260                                 for (i = 0; i < ebblock->in_count; ++i) {
7261                                         bb = ebblock->in_bb [i];
7262
7263                                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
7264                                                 cfg->cbb = bb;
7265
7266                                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
7267                                         }
7268                                 }
7269                         }
7270
7271                         cfg->cbb = ebblock;
7272                 }
7273
7274                 if (rvar) {
7275                         /*
7276                          * If the inlined method contains only a throw, then the ret var is not 
7277                          * set, so set it to a dummy value.
7278                          */
7279                         if (!ret_var_set)
7280                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
7281
7282                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
7283                         *sp++ = ins;
7284                 }
7285                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
7286                 return costs + 1;
7287         } else {
7288                 if (cfg->verbose_level > 2)
7289                         printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
7290                 cfg->exception_type = MONO_EXCEPTION_NONE;
7291
7292                 /* This gets rid of the newly added bblocks */
7293                 cfg->cbb = prev_cbb;
7294         }
7295         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
7296         return 0;
7297 }
7298
7299 /*
7300  * Some of these comments may well be out-of-date.
7301  * Design decisions: we do a single pass over the IL code (and we do bblock 
7302  * splitting/merging in the few cases when it's required: a back jump to an IL
7303  * address that was not already seen as bblock starting point).
7304  * Code is validated as we go (full verification is still better left to metadata/verify.c).
7305  * Complex operations are decomposed in simpler ones right away. We need to let the 
7306  * arch-specific code peek and poke inside this process somehow (except when the 
7307  * optimizations can take advantage of the full semantic info of coarse opcodes).
7308  * All the opcodes of the form opcode.s are 'normalized' to opcode.
7309  * MonoInst->opcode initially is the IL opcode or some simplification of that 
7310  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
7311  * opcode with value bigger than OP_LAST.
7312  * At this point the IR can be handed over to an interpreter, a dumb code generator
7313  * or to the optimizing code generator that will translate it to SSA form.
7314  *
7315  * Profiling directed optimizations.
7316  * We may compile by default with few or no optimizations and instrument the code
7317  * or the user may indicate what methods to optimize the most either in a config file
7318  * or through repeated runs where the compiler applies offline the optimizations to 
7319  * each method and then decides if it was worth it.
7320  */
7321
7322 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
7323 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
7324 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
7325 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
7326 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
7327 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
7328 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
7329 #define CHECK_TYPELOAD(klass) if (!(klass) || mono_class_has_failure (klass)) TYPE_LOAD_ERROR ((klass))
7330
7331 /* offset from br.s -> br like opcodes */
7332 #define BIG_BRANCH_OFFSET 13
7333
7334 static gboolean
7335 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
7336 {
7337         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
7338
7339         return b == NULL || b == bb;
7340 }
7341
7342 static int
7343 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
7344 {
7345         unsigned char *ip = start;
7346         unsigned char *target;
7347         int i;
7348         guint cli_addr;
7349         MonoBasicBlock *bblock;
7350         const MonoOpcode *opcode;
7351
7352         while (ip < end) {
7353                 cli_addr = ip - start;
7354                 i = mono_opcode_value ((const guint8 **)&ip, end);
7355                 if (i < 0)
7356                         UNVERIFIED;
7357                 opcode = &mono_opcodes [i];
7358                 switch (opcode->argument) {
7359                 case MonoInlineNone:
7360                         ip++; 
7361                         break;
7362                 case MonoInlineString:
7363                 case MonoInlineType:
7364                 case MonoInlineField:
7365                 case MonoInlineMethod:
7366                 case MonoInlineTok:
7367                 case MonoInlineSig:
7368                 case MonoShortInlineR:
7369                 case MonoInlineI:
7370                         ip += 5;
7371                         break;
7372                 case MonoInlineVar:
7373                         ip += 3;
7374                         break;
7375                 case MonoShortInlineVar:
7376                 case MonoShortInlineI:
7377                         ip += 2;
7378                         break;
7379                 case MonoShortInlineBrTarget:
7380                         target = start + cli_addr + 2 + (signed char)ip [1];
7381                         GET_BBLOCK (cfg, bblock, target);
7382                         ip += 2;
7383                         if (ip < end)
7384                                 GET_BBLOCK (cfg, bblock, ip);
7385                         break;
7386                 case MonoInlineBrTarget:
7387                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
7388                         GET_BBLOCK (cfg, bblock, target);
7389                         ip += 5;
7390                         if (ip < end)
7391                                 GET_BBLOCK (cfg, bblock, ip);
7392                         break;
7393                 case MonoInlineSwitch: {
7394                         guint32 n = read32 (ip + 1);
7395                         guint32 j;
7396                         ip += 5;
7397                         cli_addr += 5 + 4 * n;
7398                         target = start + cli_addr;
7399                         GET_BBLOCK (cfg, bblock, target);
7400                         
7401                         for (j = 0; j < n; ++j) {
7402                                 target = start + cli_addr + (gint32)read32 (ip);
7403                                 GET_BBLOCK (cfg, bblock, target);
7404                                 ip += 4;
7405                         }
7406                         break;
7407                 }
7408                 case MonoInlineR:
7409                 case MonoInlineI8:
7410                         ip += 9;
7411                         break;
7412                 default:
7413                         g_assert_not_reached ();
7414                 }
7415
7416                 if (i == CEE_THROW) {
7417                         unsigned char *bb_start = ip - 1;
7418                         
7419                         /* Find the start of the bblock containing the throw */
7420                         bblock = NULL;
7421                         while ((bb_start >= start) && !bblock) {
7422                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
7423                                 bb_start --;
7424                         }
7425                         if (bblock)
7426                                 bblock->out_of_line = 1;
7427                 }
7428         }
7429         return 0;
7430 unverified:
7431 exception_exit:
7432         *pos = ip;
7433         return 1;
7434 }
7435
7436 static inline MonoMethod *
7437 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context, MonoError *error)
7438 {
7439         MonoMethod *method;
7440
7441         mono_error_init (error);
7442
7443         if (m->wrapper_type != MONO_WRAPPER_NONE) {
7444                 method = (MonoMethod *)mono_method_get_wrapper_data (m, token);
7445                 if (context) {
7446                         method = mono_class_inflate_generic_method_checked (method, context, error);
7447                 }
7448         } else {
7449                 method = mono_get_method_checked (m->klass->image, token, klass, context, error);
7450         }
7451
7452         return method;
7453 }
7454
7455 static inline MonoMethod *
7456 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
7457 {
7458         MonoError error;
7459         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context, cfg ? &cfg->error : &error);
7460
7461         if (method && cfg && !cfg->gshared && mono_class_is_open_constructed_type (&method->klass->byval_arg)) {
7462                 mono_error_set_bad_image (&cfg->error, cfg->method->klass->image, "Method with open type while not compiling gshared");
7463                 method = NULL;
7464         }
7465
7466         if (!method && !cfg)
7467                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
7468
7469         return method;
7470 }
7471
7472 static inline MonoClass*
7473 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
7474 {
7475         MonoError error;
7476         MonoClass *klass;
7477
7478         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7479                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
7480                 if (context) {
7481                         klass = mono_class_inflate_generic_class_checked (klass, context, &error);
7482                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7483                 }
7484         } else {
7485                 klass = mono_class_get_and_inflate_typespec_checked (method->klass->image, token, context, &error);
7486                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
7487         }
7488         if (klass)
7489                 mono_class_init (klass);
7490         return klass;
7491 }
7492
7493 static inline MonoMethodSignature*
7494 mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context, MonoError *error)
7495 {
7496         MonoMethodSignature *fsig;
7497
7498         mono_error_init (error);
7499         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7500                 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
7501         } else {
7502                 fsig = mono_metadata_parse_signature_checked (method->klass->image, token, error);
7503                 return_val_if_nok (error, NULL);
7504         }
7505         if (context) {
7506                 fsig = mono_inflate_generic_signature(fsig, context, error);
7507         }
7508         return fsig;
7509 }
7510
7511 static MonoMethod*
7512 throw_exception (void)
7513 {
7514         static MonoMethod *method = NULL;
7515
7516         if (!method) {
7517                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
7518                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
7519         }
7520         g_assert (method);
7521         return method;
7522 }
7523
7524 static void
7525 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
7526 {
7527         MonoMethod *thrower = throw_exception ();
7528         MonoInst *args [1];
7529
7530         EMIT_NEW_PCONST (cfg, args [0], ex);
7531         mono_emit_method_call (cfg, thrower, args, NULL);
7532 }
7533
7534 /*
7535  * Return the original method is a wrapper is specified. We can only access 
7536  * the custom attributes from the original method.
7537  */
7538 static MonoMethod*
7539 get_original_method (MonoMethod *method)
7540 {
7541         if (method->wrapper_type == MONO_WRAPPER_NONE)
7542                 return method;
7543
7544         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
7545         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
7546                 return NULL;
7547
7548         /* in other cases we need to find the original method */
7549         return mono_marshal_method_from_wrapper (method);
7550 }
7551
7552 static void
7553 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field)
7554 {
7555         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7556         MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
7557         if (ex)
7558                 emit_throw_exception (cfg, ex);
7559 }
7560
7561 static void
7562 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
7563 {
7564         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7565         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
7566         if (ex)
7567                 emit_throw_exception (cfg, ex);
7568 }
7569
7570 /*
7571  * Check that the IL instructions at ip are the array initialization
7572  * sequence and return the pointer to the data and the size.
7573  */
7574 static const char*
7575 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
7576 {
7577         /*
7578          * newarr[System.Int32]
7579          * dup
7580          * ldtoken field valuetype ...
7581          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
7582          */
7583         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
7584                 MonoError error;
7585                 guint32 token = read32 (ip + 7);
7586                 guint32 field_token = read32 (ip + 2);
7587                 guint32 field_index = field_token & 0xffffff;
7588                 guint32 rva;
7589                 const char *data_ptr;
7590                 int size = 0;
7591                 MonoMethod *cmethod;
7592                 MonoClass *dummy_class;
7593                 MonoClassField *field = mono_field_from_token_checked (method->klass->image, field_token, &dummy_class, NULL, &error);
7594                 int dummy_align;
7595
7596                 if (!field) {
7597                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7598                         return NULL;
7599                 }
7600
7601                 *out_field_token = field_token;
7602
7603                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
7604                 if (!cmethod)
7605                         return NULL;
7606                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
7607                         return NULL;
7608                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
7609                 case MONO_TYPE_BOOLEAN:
7610                 case MONO_TYPE_I1:
7611                 case MONO_TYPE_U1:
7612                         size = 1; break;
7613                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
7614 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
7615                 case MONO_TYPE_CHAR:
7616                 case MONO_TYPE_I2:
7617                 case MONO_TYPE_U2:
7618                         size = 2; break;
7619                 case MONO_TYPE_I4:
7620                 case MONO_TYPE_U4:
7621                 case MONO_TYPE_R4:
7622                         size = 4; break;
7623                 case MONO_TYPE_R8:
7624                 case MONO_TYPE_I8:
7625                 case MONO_TYPE_U8:
7626                         size = 8; break;
7627 #endif
7628                 default:
7629                         return NULL;
7630                 }
7631                 size *= len;
7632                 if (size > mono_type_size (field->type, &dummy_align))
7633                     return NULL;
7634                 *out_size = size;
7635                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
7636                 if (!image_is_dynamic (method->klass->image)) {
7637                         field_index = read32 (ip + 2) & 0xffffff;
7638                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
7639                         data_ptr = mono_image_rva_map (method->klass->image, rva);
7640                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
7641                         /* for aot code we do the lookup on load */
7642                         if (aot && data_ptr)
7643                                 return (const char *)GUINT_TO_POINTER (rva);
7644                 } else {
7645                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
7646                         g_assert (!aot);
7647                         data_ptr = mono_field_get_data (field);
7648                 }
7649                 return data_ptr;
7650         }
7651         return NULL;
7652 }
7653
7654 static void
7655 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
7656 {
7657         MonoError error;
7658         char *method_fname = mono_method_full_name (method, TRUE);
7659         char *method_code;
7660         MonoMethodHeader *header = mono_method_get_header_checked (method, &error);
7661
7662         if (!header) {
7663                 method_code = g_strdup_printf ("could not parse method body due to %s", mono_error_get_message (&error));
7664                 mono_error_cleanup (&error);
7665         } else if (header->code_size == 0)
7666                 method_code = g_strdup ("method body is empty.");
7667         else
7668                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
7669         mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code));
7670         g_free (method_fname);
7671         g_free (method_code);
7672         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
7673 }
7674
7675 static void
7676 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
7677 {
7678         MonoInst *ins;
7679         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
7680         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
7681                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
7682                 /* Optimize reg-reg moves away */
7683                 /* 
7684                  * Can't optimize other opcodes, since sp[0] might point to
7685                  * the last ins of a decomposed opcode.
7686                  */
7687                 sp [0]->dreg = (cfg)->locals [n]->dreg;
7688         } else {
7689                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
7690         }
7691 }
7692
7693 /*
7694  * ldloca inhibits many optimizations so try to get rid of it in common
7695  * cases.
7696  */
7697 static inline unsigned char *
7698 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
7699 {
7700         int local, token;
7701         MonoClass *klass;
7702         MonoType *type;
7703
7704         if (size == 1) {
7705                 local = ip [1];
7706                 ip += 2;
7707         } else {
7708                 local = read16 (ip + 2);
7709                 ip += 4;
7710         }
7711         
7712         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
7713                 /* From the INITOBJ case */
7714                 token = read32 (ip + 2);
7715                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
7716                 CHECK_TYPELOAD (klass);
7717                 type = mini_get_underlying_type (&klass->byval_arg);
7718                 emit_init_local (cfg, local, type, TRUE);
7719                 return ip + 6;
7720         }
7721  exception_exit:
7722         return NULL;
7723 }
7724
7725 static MonoInst*
7726 emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used, MonoInst **sp)
7727 {
7728         MonoInst *icall_args [16];
7729         MonoInst *call_target, *ins, *vtable_ins;
7730         int arg_reg, this_reg, vtable_reg;
7731         gboolean is_iface = mono_class_is_interface (cmethod->klass);
7732         gboolean is_gsharedvt = cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig);
7733         gboolean variant_iface = FALSE;
7734         guint32 slot;
7735         int offset;
7736
7737         /*
7738          * In llvm-only mode, vtables contain function descriptors instead of
7739          * method addresses/trampolines.
7740          */
7741         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
7742
7743         if (is_iface)
7744                 slot = mono_method_get_imt_slot (cmethod);
7745         else
7746                 slot = mono_method_get_vtable_index (cmethod);
7747
7748         this_reg = sp [0]->dreg;
7749
7750         if (is_iface && mono_class_has_variant_generic_params (cmethod->klass))
7751                 variant_iface = TRUE;
7752
7753         if (!fsig->generic_param_count && !is_iface && !is_gsharedvt) {
7754                 /*
7755                  * The simplest case, a normal virtual call.
7756                  */
7757                 int slot_reg = alloc_preg (cfg);
7758                 int addr_reg = alloc_preg (cfg);
7759                 int arg_reg = alloc_preg (cfg);
7760                 MonoBasicBlock *non_null_bb;
7761
7762                 vtable_reg = alloc_preg (cfg);
7763                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7764                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + (slot * SIZEOF_VOID_P);
7765
7766                 /* Load the vtable slot, which contains a function descriptor. */
7767                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7768
7769                 NEW_BBLOCK (cfg, non_null_bb);
7770
7771                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, slot_reg, 0);
7772                 cfg->cbb->last_ins->flags |= MONO_INST_LIKELY;
7773                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, non_null_bb);
7774
7775                 /* Slow path */
7776                 // FIXME: Make the wrapper use the preserveall cconv
7777                 // FIXME: Use one icall per slot for small slot numbers ?
7778                 icall_args [0] = vtable_ins;
7779                 EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7780                 /* Make the icall return the vtable slot value to save some code space */
7781                 ins = mono_emit_jit_icall (cfg, mono_init_vtable_slot, icall_args);
7782                 ins->dreg = slot_reg;
7783                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, non_null_bb);
7784
7785                 /* Fastpath */
7786                 MONO_START_BB (cfg, non_null_bb);
7787                 /* Load the address + arg from the vtable slot */
7788                 EMIT_NEW_LOAD_MEMBASE (cfg, call_target, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7789                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, arg_reg, slot_reg, SIZEOF_VOID_P);
7790
7791                 return emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
7792         }
7793
7794         if (!fsig->generic_param_count && is_iface && !variant_iface && !is_gsharedvt) {
7795                 /*
7796                  * A simple interface call
7797                  *
7798                  * We make a call through an imt slot to obtain the function descriptor we need to call.
7799                  * The imt slot contains a function descriptor for a runtime function + arg.
7800                  */
7801                 int slot_reg = alloc_preg (cfg);
7802                 int addr_reg = alloc_preg (cfg);
7803                 int arg_reg = alloc_preg (cfg);
7804                 MonoInst *thunk_addr_ins, *thunk_arg_ins, *ftndesc_ins;
7805
7806                 vtable_reg = alloc_preg (cfg);
7807                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7808                 offset = ((gint32)slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
7809
7810                 /*
7811                  * The slot is already initialized when the vtable is created so there is no need
7812                  * to check it here.
7813                  */
7814
7815                 /* Load the imt slot, which contains a function descriptor. */
7816                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7817
7818                 /* Load the address + arg of the imt thunk from the imt slot */
7819                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_addr_ins, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7820                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_arg_ins, OP_LOAD_MEMBASE, arg_reg, slot_reg, SIZEOF_VOID_P);
7821                 /*
7822                  * IMT thunks in llvm-only mode are C functions which take an info argument
7823                  * plus the imt method and return the ftndesc to call.
7824                  */
7825                 icall_args [0] = thunk_arg_ins;
7826                 icall_args [1] = emit_get_rgctx_method (cfg, context_used,
7827                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7828                 ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_trampoline, icall_args, thunk_addr_ins, NULL, NULL);
7829
7830                 return emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
7831         }
7832
7833         if ((fsig->generic_param_count || variant_iface) && !is_gsharedvt) {
7834                 /*
7835                  * This is similar to the interface case, the vtable slot points to an imt thunk which is
7836                  * dynamically extended as more instantiations are discovered.
7837                  * This handles generic virtual methods both on classes and interfaces.
7838                  */
7839                 int slot_reg = alloc_preg (cfg);
7840                 int addr_reg = alloc_preg (cfg);
7841                 int arg_reg = alloc_preg (cfg);
7842                 int ftndesc_reg = alloc_preg (cfg);
7843                 MonoInst *thunk_addr_ins, *thunk_arg_ins, *ftndesc_ins;
7844                 MonoBasicBlock *slowpath_bb, *end_bb;
7845
7846                 NEW_BBLOCK (cfg, slowpath_bb);
7847                 NEW_BBLOCK (cfg, end_bb);
7848
7849                 vtable_reg = alloc_preg (cfg);
7850                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7851                 if (is_iface)
7852                         offset = ((gint32)slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
7853                 else
7854                         offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + (slot * SIZEOF_VOID_P);
7855
7856                 /* Load the slot, which contains a function descriptor. */
7857                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7858
7859                 /* These slots are not initialized, so fall back to the slow path until they are initialized */
7860                 /* That happens when mono_method_add_generic_virtual_invocation () creates an IMT thunk */
7861                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, slot_reg, 0);
7862                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, slowpath_bb);
7863
7864                 /* Fastpath */
7865                 /* Same as with iface calls */
7866                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_addr_ins, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7867                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_arg_ins, OP_LOAD_MEMBASE, arg_reg, slot_reg, SIZEOF_VOID_P);
7868                 icall_args [0] = thunk_arg_ins;
7869                 icall_args [1] = emit_get_rgctx_method (cfg, context_used,
7870                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7871                 ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_trampoline, icall_args, thunk_addr_ins, NULL, NULL);
7872                 ftndesc_ins->dreg = ftndesc_reg;
7873                 /*
7874                  * Unlike normal iface calls, these imt thunks can return NULL, i.e. when they are passed an instantiation
7875                  * they don't know about yet. Fall back to the slowpath in that case.
7876                  */
7877                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ftndesc_reg, 0);
7878                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, slowpath_bb);
7879
7880                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
7881
7882                 /* Slowpath */
7883                 MONO_START_BB (cfg, slowpath_bb);
7884                 icall_args [0] = vtable_ins;
7885                 EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7886                 icall_args [2] = emit_get_rgctx_method (cfg, context_used,
7887                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7888                 if (is_iface)
7889                         ftndesc_ins = mono_emit_jit_icall (cfg, mono_resolve_generic_virtual_iface_call, icall_args);
7890                 else
7891                         ftndesc_ins = mono_emit_jit_icall (cfg, mono_resolve_generic_virtual_call, icall_args);
7892                 ftndesc_ins->dreg = ftndesc_reg;
7893                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
7894
7895                 /* Common case */
7896                 MONO_START_BB (cfg, end_bb);
7897                 return emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
7898         }
7899
7900         /*
7901          * Non-optimized cases
7902          */
7903         icall_args [0] = sp [0];
7904         EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7905
7906         icall_args [2] = emit_get_rgctx_method (cfg, context_used,
7907                                                                                         cmethod, MONO_RGCTX_INFO_METHOD);
7908
7909         arg_reg = alloc_preg (cfg);
7910         MONO_EMIT_NEW_PCONST (cfg, arg_reg, NULL);
7911         EMIT_NEW_VARLOADA_VREG (cfg, icall_args [3], arg_reg, &mono_defaults.int_class->byval_arg);
7912
7913         g_assert (is_gsharedvt);
7914         if (is_iface)
7915                 call_target = mono_emit_jit_icall (cfg, mono_resolve_iface_call_gsharedvt, icall_args);
7916         else
7917                 call_target = mono_emit_jit_icall (cfg, mono_resolve_vcall_gsharedvt, icall_args);
7918
7919         /*
7920          * Pass the extra argument even if the callee doesn't receive it, most
7921          * calling conventions allow this.
7922          */
7923         return emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
7924 }
7925
7926 static gboolean
7927 is_exception_class (MonoClass *klass)
7928 {
7929         while (klass) {
7930                 if (klass == mono_defaults.exception_class)
7931                         return TRUE;
7932                 klass = klass->parent;
7933         }
7934         return FALSE;
7935 }
7936
7937 /*
7938  * is_jit_optimizer_disabled:
7939  *
7940  *   Determine whenever M's assembly has a DebuggableAttribute with the
7941  * IsJITOptimizerDisabled flag set.
7942  */
7943 static gboolean
7944 is_jit_optimizer_disabled (MonoMethod *m)
7945 {
7946         MonoError error;
7947         MonoAssembly *ass = m->klass->image->assembly;
7948         MonoCustomAttrInfo* attrs;
7949         MonoClass *klass;
7950         int i;
7951         gboolean val = FALSE;
7952
7953         g_assert (ass);
7954         if (ass->jit_optimizer_disabled_inited)
7955                 return ass->jit_optimizer_disabled;
7956
7957         klass = mono_class_try_get_debuggable_attribute_class ();
7958
7959         if (!klass) {
7960                 /* Linked away */
7961                 ass->jit_optimizer_disabled = FALSE;
7962                 mono_memory_barrier ();
7963                 ass->jit_optimizer_disabled_inited = TRUE;
7964                 return FALSE;
7965         }
7966
7967         attrs = mono_custom_attrs_from_assembly_checked (ass, FALSE, &error);
7968         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7969         if (attrs) {
7970                 for (i = 0; i < attrs->num_attrs; ++i) {
7971                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
7972                         const gchar *p;
7973                         MonoMethodSignature *sig;
7974
7975                         if (!attr->ctor || attr->ctor->klass != klass)
7976                                 continue;
7977                         /* Decode the attribute. See reflection.c */
7978                         p = (const char*)attr->data;
7979                         g_assert (read16 (p) == 0x0001);
7980                         p += 2;
7981
7982                         // FIXME: Support named parameters
7983                         sig = mono_method_signature (attr->ctor);
7984                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
7985                                 continue;
7986                         /* Two boolean arguments */
7987                         p ++;
7988                         val = *p;
7989                 }
7990                 mono_custom_attrs_free (attrs);
7991         }
7992
7993         ass->jit_optimizer_disabled = val;
7994         mono_memory_barrier ();
7995         ass->jit_optimizer_disabled_inited = TRUE;
7996
7997         return val;
7998 }
7999
8000 static gboolean
8001 is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig, int call_opcode)
8002 {
8003         gboolean supported_tail_call;
8004         int i;
8005
8006         supported_tail_call = mono_arch_tail_call_supported (cfg, mono_method_signature (method), mono_method_signature (cmethod));
8007
8008         for (i = 0; i < fsig->param_count; ++i) {
8009                 if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
8010                         /* These can point to the current method's stack */
8011                         supported_tail_call = FALSE;
8012         }
8013         if (fsig->hasthis && cmethod->klass->valuetype)
8014                 /* this might point to the current method's stack */
8015                 supported_tail_call = FALSE;
8016         if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
8017                 supported_tail_call = FALSE;
8018         if (cfg->method->save_lmf)
8019                 supported_tail_call = FALSE;
8020         if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
8021                 supported_tail_call = FALSE;
8022         if (call_opcode != CEE_CALL)
8023                 supported_tail_call = FALSE;
8024
8025         /* Debugging support */
8026 #if 0
8027         if (supported_tail_call) {
8028                 if (!mono_debug_count ())
8029                         supported_tail_call = FALSE;
8030         }
8031 #endif
8032
8033         return supported_tail_call;
8034 }
8035
8036 /*
8037  * handle_ctor_call:
8038  *
8039  *   Handle calls made to ctors from NEWOBJ opcodes.
8040  */
8041 static void
8042 handle_ctor_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used,
8043                                   MonoInst **sp, guint8 *ip, int *inline_costs)
8044 {
8045         MonoInst *vtable_arg = NULL, *callvirt_this_arg = NULL, *ins;
8046
8047         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
8048                                         mono_method_is_generic_sharable (cmethod, TRUE)) {
8049                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
8050                         mono_class_vtable (cfg->domain, cmethod->klass);
8051                         CHECK_TYPELOAD (cmethod->klass);
8052
8053                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
8054                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
8055                 } else {
8056                         if (context_used) {
8057                                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
8058                                                                                                    cmethod->klass, MONO_RGCTX_INFO_VTABLE);
8059                         } else {
8060                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
8061
8062                                 CHECK_TYPELOAD (cmethod->klass);
8063                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
8064                         }
8065                 }
8066         }
8067
8068         /* Avoid virtual calls to ctors if possible */
8069         if (mono_class_is_marshalbyref (cmethod->klass))
8070                 callvirt_this_arg = sp [0];
8071
8072         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
8073                 g_assert (MONO_TYPE_IS_VOID (fsig->ret));
8074                 CHECK_CFG_EXCEPTION;
8075         } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
8076                            mono_method_check_inlining (cfg, cmethod) &&
8077                            !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE)) {
8078                 int costs;
8079
8080                 if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, FALSE))) {
8081                         cfg->real_offset += 5;
8082
8083                         *inline_costs += costs - 5;
8084                 } else {
8085                         INLINE_FAILURE ("inline failure");
8086                         // FIXME-VT: Clean this up
8087                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
8088                                 GSHAREDVT_FAILURE(*ip);
8089                         mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
8090                 }
8091         } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
8092                 MonoInst *addr;
8093
8094                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
8095
8096                 if (cfg->llvm_only) {
8097                         // FIXME: Avoid initializing vtable_arg
8098                         emit_llvmonly_calli (cfg, fsig, sp, addr);
8099                 } else {
8100                         mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
8101                 }
8102         } else if (context_used &&
8103                            ((!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
8104                                  !mono_class_generic_sharing_enabled (cmethod->klass)) || cfg->gsharedvt)) {
8105                 MonoInst *cmethod_addr;
8106
8107                 /* Generic calls made out of gsharedvt methods cannot be patched, so use an indirect call */
8108
8109                 if (cfg->llvm_only) {
8110                         MonoInst *addr = emit_get_rgctx_method (cfg, context_used, cmethod,
8111                                                                                                         MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
8112                         emit_llvmonly_calli (cfg, fsig, sp, addr);
8113                 } else {
8114                         cmethod_addr = emit_get_rgctx_method (cfg, context_used,
8115                                                                                                   cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
8116
8117                         mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
8118                 }
8119         } else {
8120                 INLINE_FAILURE ("ctor call");
8121                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
8122                                                                                   callvirt_this_arg, NULL, vtable_arg);
8123         }
8124  exception_exit:
8125         return;
8126 }
8127
8128 static void
8129 emit_setret (MonoCompile *cfg, MonoInst *val)
8130 {
8131         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (cfg->method)->ret);
8132         MonoInst *ins;
8133
8134         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
8135                 MonoInst *ret_addr;
8136
8137                 if (!cfg->vret_addr) {
8138                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, val);
8139                 } else {
8140                         EMIT_NEW_RETLOADA (cfg, ret_addr);
8141
8142                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, val->dreg);
8143                         ins->klass = mono_class_from_mono_type (ret_type);
8144                 }
8145         } else {
8146 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
8147                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
8148                         MonoInst *iargs [1];
8149                         MonoInst *conv;
8150
8151                         iargs [0] = val;
8152                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
8153                         mono_arch_emit_setret (cfg, cfg->method, conv);
8154                 } else {
8155                         mono_arch_emit_setret (cfg, cfg->method, val);
8156                 }
8157 #else
8158                 mono_arch_emit_setret (cfg, cfg->method, val);
8159 #endif
8160         }
8161 }
8162
8163 /*
8164  * mono_method_to_ir:
8165  *
8166  * Translate the .net IL into linear IR.
8167  *
8168  * @start_bblock: if not NULL, the starting basic block, used during inlining.
8169  * @end_bblock: if not NULL, the ending basic block, used during inlining.
8170  * @return_var: if not NULL, the place where the return value is stored, used during inlining.   
8171  * @inline_args: if not NULL, contains the arguments to the inline call
8172  * @inline_offset: if not zero, the real offset from the inline call, or zero otherwise.
8173  * @is_virtual_call: whether this method is being called as a result of a call to callvirt
8174  *
8175  * This method is used to turn ECMA IL into Mono's internal Linear IR
8176  * reprensetation.  It is used both for entire methods, as well as
8177  * inlining existing methods.  In the former case, the @start_bblock,
8178  * @end_bblock, @return_var, @inline_args are all set to NULL, and the
8179  * inline_offset is set to zero.
8180  * 
8181  * Returns: the inline cost, or -1 if there was an error processing this method.
8182  */
8183 int
8184 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
8185                    MonoInst *return_var, MonoInst **inline_args, 
8186                    guint inline_offset, gboolean is_virtual_call)
8187 {
8188         MonoError error;
8189         MonoInst *ins, **sp, **stack_start;
8190         MonoBasicBlock *tblock = NULL, *init_localsbb = NULL;
8191         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
8192         MonoMethod *cmethod, *method_definition;
8193         MonoInst **arg_array;
8194         MonoMethodHeader *header;
8195         MonoImage *image;
8196         guint32 token, ins_flag;
8197         MonoClass *klass;
8198         MonoClass *constrained_class = NULL;
8199         unsigned char *ip, *end, *target, *err_pos;
8200         MonoMethodSignature *sig;
8201         MonoGenericContext *generic_context = NULL;
8202         MonoGenericContainer *generic_container = NULL;
8203         MonoType **param_types;
8204         int i, n, start_new_bblock, dreg;
8205         int num_calls = 0, inline_costs = 0;
8206         int breakpoint_id = 0;
8207         guint num_args;
8208         GSList *class_inits = NULL;
8209         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
8210         int context_used;
8211         gboolean init_locals, seq_points, skip_dead_blocks;
8212         gboolean sym_seq_points = FALSE;
8213         MonoDebugMethodInfo *minfo;
8214         MonoBitSet *seq_point_locs = NULL;
8215         MonoBitSet *seq_point_set_locs = NULL;
8216
8217         cfg->disable_inline = is_jit_optimizer_disabled (method);
8218
8219         /* serialization and xdomain stuff may need access to private fields and methods */
8220         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
8221         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
8222         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
8223         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
8224         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
8225         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
8226
8227         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
8228         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
8229         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
8230         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
8231         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
8232
8233         image = method->klass->image;
8234         header = mono_method_get_header_checked (method, &cfg->error);
8235         if (!header) {
8236                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
8237                 goto exception_exit;
8238         } else {
8239                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
8240         }
8241
8242         generic_container = mono_method_get_generic_container (method);
8243         sig = mono_method_signature (method);
8244         num_args = sig->hasthis + sig->param_count;
8245         ip = (unsigned char*)header->code;
8246         cfg->cil_start = ip;
8247         end = ip + header->code_size;
8248         cfg->stat_cil_code_size += header->code_size;
8249
8250         seq_points = cfg->gen_seq_points && cfg->method == method;
8251
8252         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
8253                 /* We could hit a seq point before attaching to the JIT (#8338) */
8254                 seq_points = FALSE;
8255         }
8256
8257         if (cfg->gen_sdb_seq_points && cfg->method == method) {
8258                 minfo = mono_debug_lookup_method (method);
8259                 if (minfo) {
8260                         MonoSymSeqPoint *sps;
8261                         int i, n_il_offsets;
8262
8263                         mono_debug_get_seq_points (minfo, NULL, NULL, NULL, &sps, &n_il_offsets);
8264                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
8265                         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);
8266                         sym_seq_points = TRUE;
8267                         for (i = 0; i < n_il_offsets; ++i) {
8268                                 if (sps [i].il_offset < header->code_size)
8269                                         mono_bitset_set_fast (seq_point_locs, sps [i].il_offset);
8270                         }
8271                         g_free (sps);
8272                 } else if (!method->wrapper_type && !method->dynamic && mono_debug_image_has_debug_info (method->klass->image)) {
8273                         /* Methods without line number info like auto-generated property accessors */
8274                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
8275                         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);
8276                         sym_seq_points = TRUE;
8277                 }
8278         }
8279
8280         /* 
8281          * Methods without init_locals set could cause asserts in various passes
8282          * (#497220). To work around this, we emit dummy initialization opcodes
8283          * (OP_DUMMY_ICONST etc.) which generate no code. These are only supported
8284          * on some platforms.
8285          */
8286         if ((cfg->opt & MONO_OPT_UNSAFE) && cfg->backend->have_dummy_init)
8287                 init_locals = header->init_locals;
8288         else
8289                 init_locals = TRUE;
8290
8291         method_definition = method;
8292         while (method_definition->is_inflated) {
8293                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
8294                 method_definition = imethod->declaring;
8295         }
8296
8297         /* SkipVerification is not allowed if core-clr is enabled */
8298         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
8299                 dont_verify = TRUE;
8300                 dont_verify_stloc = TRUE;
8301         }
8302
8303         if (sig->is_inflated)
8304                 generic_context = mono_method_get_context (method);
8305         else if (generic_container)
8306                 generic_context = &generic_container->context;
8307         cfg->generic_context = generic_context;
8308
8309         if (!cfg->gshared)
8310                 g_assert (!sig->has_type_parameters);
8311
8312         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
8313                 g_assert (method->is_inflated);
8314                 g_assert (mono_method_get_context (method)->method_inst);
8315         }
8316         if (method->is_inflated && mono_method_get_context (method)->method_inst)
8317                 g_assert (sig->generic_param_count);
8318
8319         if (cfg->method == method) {
8320                 cfg->real_offset = 0;
8321         } else {
8322                 cfg->real_offset = inline_offset;
8323         }
8324
8325         cfg->cil_offset_to_bb = (MonoBasicBlock **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
8326         cfg->cil_offset_to_bb_len = header->code_size;
8327
8328         cfg->current_method = method;
8329
8330         if (cfg->verbose_level > 2)
8331                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
8332
8333         param_types = (MonoType **)mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
8334         if (sig->hasthis)
8335                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
8336         for (n = 0; n < sig->param_count; ++n)
8337                 param_types [n + sig->hasthis] = sig->params [n];
8338         cfg->arg_types = param_types;
8339
8340         cfg->dont_inline = g_list_prepend (cfg->dont_inline, method);
8341         if (cfg->method == method) {
8342
8343                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
8344                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
8345
8346                 /* ENTRY BLOCK */
8347                 NEW_BBLOCK (cfg, start_bblock);
8348                 cfg->bb_entry = start_bblock;
8349                 start_bblock->cil_code = NULL;
8350                 start_bblock->cil_length = 0;
8351
8352                 /* EXIT BLOCK */
8353                 NEW_BBLOCK (cfg, end_bblock);
8354                 cfg->bb_exit = end_bblock;
8355                 end_bblock->cil_code = NULL;
8356                 end_bblock->cil_length = 0;
8357                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
8358                 g_assert (cfg->num_bblocks == 2);
8359
8360                 arg_array = cfg->args;
8361
8362                 if (header->num_clauses) {
8363                         cfg->spvars = g_hash_table_new (NULL, NULL);
8364                         cfg->exvars = g_hash_table_new (NULL, NULL);
8365                 }
8366                 /* handle exception clauses */
8367                 for (i = 0; i < header->num_clauses; ++i) {
8368                         MonoBasicBlock *try_bb;
8369                         MonoExceptionClause *clause = &header->clauses [i];
8370                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
8371
8372                         try_bb->real_offset = clause->try_offset;
8373                         try_bb->try_start = TRUE;
8374                         try_bb->region = ((i + 1) << 8) | clause->flags;
8375                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
8376                         tblock->real_offset = clause->handler_offset;
8377                         tblock->flags |= BB_EXCEPTION_HANDLER;
8378
8379                         /*
8380                          * Linking the try block with the EH block hinders inlining as we won't be able to 
8381                          * merge the bblocks from inlining and produce an artificial hole for no good reason.
8382                          */
8383                         if (COMPILE_LLVM (cfg))
8384                                 link_bblock (cfg, try_bb, tblock);
8385
8386                         if (*(ip + clause->handler_offset) == CEE_POP)
8387                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
8388
8389                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
8390                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
8391                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
8392                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
8393                                 MONO_ADD_INS (tblock, ins);
8394
8395                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FILTER) {
8396                                         /* finally clauses already have a seq point */
8397                                         /* seq points for filter clauses are emitted below */
8398                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
8399                                         MONO_ADD_INS (tblock, ins);
8400                                 }
8401
8402                                 /* todo: is a fault block unsafe to optimize? */
8403                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
8404                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
8405                         }
8406
8407                         /*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);
8408                           while (p < end) {
8409                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
8410                           }*/
8411                         /* catch and filter blocks get the exception object on the stack */
8412                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
8413                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8414
8415                                 /* mostly like handle_stack_args (), but just sets the input args */
8416                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
8417                                 tblock->in_scount = 1;
8418                                 tblock->in_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
8419                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
8420
8421                                 cfg->cbb = tblock;
8422
8423 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
8424                                 /* The EH code passes in the exception in a register to both JITted and LLVM compiled code */
8425                                 if (!cfg->compile_llvm) {
8426                                         MONO_INST_NEW (cfg, ins, OP_GET_EX_OBJ);
8427                                         ins->dreg = tblock->in_stack [0]->dreg;
8428                                         MONO_ADD_INS (tblock, ins);
8429                                 }
8430 #else
8431                                 MonoInst *dummy_use;
8432
8433                                 /* 
8434                                  * Add a dummy use for the exvar so its liveness info will be
8435                                  * correct.
8436                                  */
8437                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
8438 #endif
8439
8440                                 if (seq_points && clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8441                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
8442                                         MONO_ADD_INS (tblock, ins);
8443                                 }
8444                                 
8445                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8446                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
8447                                         tblock->flags |= BB_EXCEPTION_HANDLER;
8448                                         tblock->real_offset = clause->data.filter_offset;
8449                                         tblock->in_scount = 1;
8450                                         tblock->in_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
8451                                         /* The filter block shares the exvar with the handler block */
8452                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
8453                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
8454                                         MONO_ADD_INS (tblock, ins);
8455                                 }
8456                         }
8457
8458                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
8459                                         clause->data.catch_class &&
8460                                         cfg->gshared &&
8461                                         mono_class_check_context_used (clause->data.catch_class)) {
8462                                 /*
8463                                  * In shared generic code with catch
8464                                  * clauses containing type variables
8465                                  * the exception handling code has to
8466                                  * be able to get to the rgctx.
8467                                  * Therefore we have to make sure that
8468                                  * the vtable/mrgctx argument (for
8469                                  * static or generic methods) or the
8470                                  * "this" argument (for non-static
8471                                  * methods) are live.
8472                                  */
8473                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8474                                                 mini_method_get_context (method)->method_inst ||
8475                                                 method->klass->valuetype) {
8476                                         mono_get_vtable_var (cfg);
8477                                 } else {
8478                                         MonoInst *dummy_use;
8479
8480                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
8481                                 }
8482                         }
8483                 }
8484         } else {
8485                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
8486                 cfg->cbb = start_bblock;
8487                 cfg->args = arg_array;
8488                 mono_save_args (cfg, sig, inline_args);
8489         }
8490
8491         /* FIRST CODE BLOCK */
8492         NEW_BBLOCK (cfg, tblock);
8493         tblock->cil_code = ip;
8494         cfg->cbb = tblock;
8495         cfg->ip = ip;
8496
8497         ADD_BBLOCK (cfg, tblock);
8498
8499         if (cfg->method == method) {
8500                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
8501                 if (breakpoint_id) {
8502                         MONO_INST_NEW (cfg, ins, OP_BREAK);
8503                         MONO_ADD_INS (cfg->cbb, ins);
8504                 }
8505         }
8506
8507         /* we use a separate basic block for the initialization code */
8508         NEW_BBLOCK (cfg, init_localsbb);
8509         if (cfg->method == method)
8510                 cfg->bb_init = init_localsbb;
8511         init_localsbb->real_offset = cfg->real_offset;
8512         start_bblock->next_bb = init_localsbb;
8513         init_localsbb->next_bb = cfg->cbb;
8514         link_bblock (cfg, start_bblock, init_localsbb);
8515         link_bblock (cfg, init_localsbb, cfg->cbb);
8516                 
8517         cfg->cbb = init_localsbb;
8518
8519         if (cfg->gsharedvt && cfg->method == method) {
8520                 MonoGSharedVtMethodInfo *info;
8521                 MonoInst *var, *locals_var;
8522                 int dreg;
8523
8524                 info = (MonoGSharedVtMethodInfo *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
8525                 info->method = cfg->method;
8526                 info->count_entries = 16;
8527                 info->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
8528                 cfg->gsharedvt_info = info;
8529
8530                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8531                 /* prevent it from being register allocated */
8532                 //var->flags |= MONO_INST_VOLATILE;
8533                 cfg->gsharedvt_info_var = var;
8534
8535                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
8536                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
8537
8538                 /* Allocate locals */
8539                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8540                 /* prevent it from being register allocated */
8541                 //locals_var->flags |= MONO_INST_VOLATILE;
8542                 cfg->gsharedvt_locals_var = locals_var;
8543
8544                 dreg = alloc_ireg (cfg);
8545                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
8546
8547                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
8548                 ins->dreg = locals_var->dreg;
8549                 ins->sreg1 = dreg;
8550                 MONO_ADD_INS (cfg->cbb, ins);
8551                 cfg->gsharedvt_locals_var_ins = ins;
8552                 
8553                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
8554                 /*
8555                 if (init_locals)
8556                         ins->flags |= MONO_INST_INIT;
8557                 */
8558         }
8559
8560         if (mono_security_core_clr_enabled ()) {
8561                 /* check if this is native code, e.g. an icall or a p/invoke */
8562                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
8563                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
8564                         if (wrapped) {
8565                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
8566                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
8567
8568                                 /* if this ia a native call then it can only be JITted from platform code */
8569                                 if ((icall || pinvk) && method->klass && method->klass->image) {
8570                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
8571                                                 MonoException *ex = icall ? mono_get_exception_security () : 
8572                                                         mono_get_exception_method_access ();
8573                                                 emit_throw_exception (cfg, ex);
8574                                         }
8575                                 }
8576                         }
8577                 }
8578         }
8579
8580         CHECK_CFG_EXCEPTION;
8581
8582         if (header->code_size == 0)
8583                 UNVERIFIED;
8584
8585         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
8586                 ip = err_pos;
8587                 UNVERIFIED;
8588         }
8589
8590         if (cfg->method == method)
8591                 mono_debug_init_method (cfg, cfg->cbb, breakpoint_id);
8592
8593         for (n = 0; n < header->num_locals; ++n) {
8594                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
8595                         UNVERIFIED;
8596         }
8597         class_inits = NULL;
8598
8599         /* We force the vtable variable here for all shared methods
8600            for the possibility that they might show up in a stack
8601            trace where their exact instantiation is needed. */
8602         if (cfg->gshared && method == cfg->method) {
8603                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8604                                 mini_method_get_context (method)->method_inst ||
8605                                 method->klass->valuetype) {
8606                         mono_get_vtable_var (cfg);
8607                 } else {
8608                         /* FIXME: Is there a better way to do this?
8609                            We need the variable live for the duration
8610                            of the whole method. */
8611                         cfg->args [0]->flags |= MONO_INST_VOLATILE;
8612                 }
8613         }
8614
8615         /* add a check for this != NULL to inlined methods */
8616         if (is_virtual_call) {
8617                 MonoInst *arg_ins;
8618
8619                 NEW_ARGLOAD (cfg, arg_ins, 0);
8620                 MONO_ADD_INS (cfg->cbb, arg_ins);
8621                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
8622         }
8623
8624         skip_dead_blocks = !dont_verify;
8625         if (skip_dead_blocks) {
8626                 original_bb = bb = mono_basic_block_split (method, &cfg->error, header);
8627                 CHECK_CFG_ERROR;
8628                 g_assert (bb);
8629         }
8630
8631         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
8632         stack_start = sp = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
8633
8634         ins_flag = 0;
8635         start_new_bblock = 0;
8636         while (ip < end) {
8637                 if (cfg->method == method)
8638                         cfg->real_offset = ip - header->code;
8639                 else
8640                         cfg->real_offset = inline_offset;
8641                 cfg->ip = ip;
8642
8643                 context_used = 0;
8644
8645                 if (start_new_bblock) {
8646                         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
8647                         if (start_new_bblock == 2) {
8648                                 g_assert (ip == tblock->cil_code);
8649                         } else {
8650                                 GET_BBLOCK (cfg, tblock, ip);
8651                         }
8652                         cfg->cbb->next_bb = tblock;
8653                         cfg->cbb = tblock;
8654                         start_new_bblock = 0;
8655                         for (i = 0; i < cfg->cbb->in_scount; ++i) {
8656                                 if (cfg->verbose_level > 3)
8657                                         printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8658                                 EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8659                                 *sp++ = ins;
8660                         }
8661                         if (class_inits)
8662                                 g_slist_free (class_inits);
8663                         class_inits = NULL;
8664                 } else {
8665                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != cfg->cbb)) {
8666                                 link_bblock (cfg, cfg->cbb, tblock);
8667                                 if (sp != stack_start) {
8668                                         handle_stack_args (cfg, stack_start, sp - stack_start);
8669                                         sp = stack_start;
8670                                         CHECK_UNVERIFIABLE (cfg);
8671                                 }
8672                                 cfg->cbb->next_bb = tblock;
8673                                 cfg->cbb = tblock;
8674                                 for (i = 0; i < cfg->cbb->in_scount; ++i) {
8675                                         if (cfg->verbose_level > 3)
8676                                                 printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8677                                         EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8678                                         *sp++ = ins;
8679                                 }
8680                                 g_slist_free (class_inits);
8681                                 class_inits = NULL;
8682                         }
8683                 }
8684
8685                 if (skip_dead_blocks) {
8686                         int ip_offset = ip - header->code;
8687
8688                         if (ip_offset == bb->end)
8689                                 bb = bb->next;
8690
8691                         if (bb->dead) {
8692                                 int op_size = mono_opcode_size (ip, end);
8693                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
8694
8695                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
8696
8697                                 if (ip_offset + op_size == bb->end) {
8698                                         MONO_INST_NEW (cfg, ins, OP_NOP);
8699                                         MONO_ADD_INS (cfg->cbb, ins);
8700                                         start_new_bblock = 1;
8701                                 }
8702
8703                                 ip += op_size;
8704                                 continue;
8705                         }
8706                 }
8707                 /*
8708                  * Sequence points are points where the debugger can place a breakpoint.
8709                  * Currently, we generate these automatically at points where the IL
8710                  * stack is empty.
8711                  */
8712                 if (seq_points && ((!sym_seq_points && (sp == stack_start)) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
8713                         /*
8714                          * Make methods interruptable at the beginning, and at the targets of
8715                          * backward branches.
8716                          * Also, do this at the start of every bblock in methods with clauses too,
8717                          * to be able to handle instructions with inprecise control flow like
8718                          * throw/endfinally.
8719                          * Backward branches are handled at the end of method-to-ir ().
8720                          */
8721                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
8722                         gboolean sym_seq_point = sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code);
8723
8724                         /* Avoid sequence points on empty IL like .volatile */
8725                         // FIXME: Enable this
8726                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
8727                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
8728                         if ((sp != stack_start) && !sym_seq_point)
8729                                 ins->flags |= MONO_INST_NONEMPTY_STACK;
8730                         MONO_ADD_INS (cfg->cbb, ins);
8731
8732                         if (sym_seq_points)
8733                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
8734                 }
8735
8736                 cfg->cbb->real_offset = cfg->real_offset;
8737
8738                 if ((cfg->method == method) && cfg->coverage_info) {
8739                         guint32 cil_offset = ip - header->code;
8740                         cfg->coverage_info->data [cil_offset].cil_code = ip;
8741
8742                         /* TODO: Use an increment here */
8743 #if defined(TARGET_X86)
8744                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
8745                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
8746                         ins->inst_imm = 1;
8747                         MONO_ADD_INS (cfg->cbb, ins);
8748 #else
8749                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
8750                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
8751 #endif
8752                 }
8753
8754                 if (cfg->verbose_level > 3)
8755                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
8756
8757                 switch (*ip) {
8758                 case CEE_NOP:
8759                         if (seq_points && !sym_seq_points && sp != stack_start) {
8760                                 /*
8761                                  * The C# compiler uses these nops to notify the JIT that it should
8762                                  * insert seq points.
8763                                  */
8764                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
8765                                 MONO_ADD_INS (cfg->cbb, ins);
8766                         }
8767                         if (cfg->keep_cil_nops)
8768                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
8769                         else
8770                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8771                         ip++;
8772                         MONO_ADD_INS (cfg->cbb, ins);
8773                         break;
8774                 case CEE_BREAK:
8775                         if (should_insert_brekpoint (cfg->method)) {
8776                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
8777                         } else {
8778                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8779                         }
8780                         ip++;
8781                         MONO_ADD_INS (cfg->cbb, ins);
8782                         break;
8783                 case CEE_LDARG_0:
8784                 case CEE_LDARG_1:
8785                 case CEE_LDARG_2:
8786                 case CEE_LDARG_3:
8787                         CHECK_STACK_OVF (1);
8788                         n = (*ip)-CEE_LDARG_0;
8789                         CHECK_ARG (n);
8790                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8791                         ip++;
8792                         *sp++ = ins;
8793                         break;
8794                 case CEE_LDLOC_0:
8795                 case CEE_LDLOC_1:
8796                 case CEE_LDLOC_2:
8797                 case CEE_LDLOC_3:
8798                         CHECK_STACK_OVF (1);
8799                         n = (*ip)-CEE_LDLOC_0;
8800                         CHECK_LOCAL (n);
8801                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8802                         ip++;
8803                         *sp++ = ins;
8804                         break;
8805                 case CEE_STLOC_0:
8806                 case CEE_STLOC_1:
8807                 case CEE_STLOC_2:
8808                 case CEE_STLOC_3: {
8809                         CHECK_STACK (1);
8810                         n = (*ip)-CEE_STLOC_0;
8811                         CHECK_LOCAL (n);
8812                         --sp;
8813                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
8814                                 UNVERIFIED;
8815                         emit_stloc_ir (cfg, sp, header, n);
8816                         ++ip;
8817                         inline_costs += 1;
8818                         break;
8819                         }
8820                 case CEE_LDARG_S:
8821                         CHECK_OPSIZE (2);
8822                         CHECK_STACK_OVF (1);
8823                         n = ip [1];
8824                         CHECK_ARG (n);
8825                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8826                         *sp++ = ins;
8827                         ip += 2;
8828                         break;
8829                 case CEE_LDARGA_S:
8830                         CHECK_OPSIZE (2);
8831                         CHECK_STACK_OVF (1);
8832                         n = ip [1];
8833                         CHECK_ARG (n);
8834                         NEW_ARGLOADA (cfg, ins, n);
8835                         MONO_ADD_INS (cfg->cbb, ins);
8836                         *sp++ = ins;
8837                         ip += 2;
8838                         break;
8839                 case CEE_STARG_S:
8840                         CHECK_OPSIZE (2);
8841                         CHECK_STACK (1);
8842                         --sp;
8843                         n = ip [1];
8844                         CHECK_ARG (n);
8845                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
8846                                 UNVERIFIED;
8847                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
8848                         ip += 2;
8849                         break;
8850                 case CEE_LDLOC_S:
8851                         CHECK_OPSIZE (2);
8852                         CHECK_STACK_OVF (1);
8853                         n = ip [1];
8854                         CHECK_LOCAL (n);
8855                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8856                         *sp++ = ins;
8857                         ip += 2;
8858                         break;
8859                 case CEE_LDLOCA_S: {
8860                         unsigned char *tmp_ip;
8861                         CHECK_OPSIZE (2);
8862                         CHECK_STACK_OVF (1);
8863                         CHECK_LOCAL (ip [1]);
8864
8865                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
8866                                 ip = tmp_ip;
8867                                 inline_costs += 1;
8868                                 break;
8869                         }
8870
8871                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
8872                         *sp++ = ins;
8873                         ip += 2;
8874                         break;
8875                 }
8876                 case CEE_STLOC_S:
8877                         CHECK_OPSIZE (2);
8878                         CHECK_STACK (1);
8879                         --sp;
8880                         CHECK_LOCAL (ip [1]);
8881                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
8882                                 UNVERIFIED;
8883                         emit_stloc_ir (cfg, sp, header, ip [1]);
8884                         ip += 2;
8885                         inline_costs += 1;
8886                         break;
8887                 case CEE_LDNULL:
8888                         CHECK_STACK_OVF (1);
8889                         EMIT_NEW_PCONST (cfg, ins, NULL);
8890                         ins->type = STACK_OBJ;
8891                         ++ip;
8892                         *sp++ = ins;
8893                         break;
8894                 case CEE_LDC_I4_M1:
8895                         CHECK_STACK_OVF (1);
8896                         EMIT_NEW_ICONST (cfg, ins, -1);
8897                         ++ip;
8898                         *sp++ = ins;
8899                         break;
8900                 case CEE_LDC_I4_0:
8901                 case CEE_LDC_I4_1:
8902                 case CEE_LDC_I4_2:
8903                 case CEE_LDC_I4_3:
8904                 case CEE_LDC_I4_4:
8905                 case CEE_LDC_I4_5:
8906                 case CEE_LDC_I4_6:
8907                 case CEE_LDC_I4_7:
8908                 case CEE_LDC_I4_8:
8909                         CHECK_STACK_OVF (1);
8910                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
8911                         ++ip;
8912                         *sp++ = ins;
8913                         break;
8914                 case CEE_LDC_I4_S:
8915                         CHECK_OPSIZE (2);
8916                         CHECK_STACK_OVF (1);
8917                         ++ip;
8918                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
8919                         ++ip;
8920                         *sp++ = ins;
8921                         break;
8922                 case CEE_LDC_I4:
8923                         CHECK_OPSIZE (5);
8924                         CHECK_STACK_OVF (1);
8925                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
8926                         ip += 5;
8927                         *sp++ = ins;
8928                         break;
8929                 case CEE_LDC_I8:
8930                         CHECK_OPSIZE (9);
8931                         CHECK_STACK_OVF (1);
8932                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
8933                         ins->type = STACK_I8;
8934                         ins->dreg = alloc_dreg (cfg, STACK_I8);
8935                         ++ip;
8936                         ins->inst_l = (gint64)read64 (ip);
8937                         MONO_ADD_INS (cfg->cbb, ins);
8938                         ip += 8;
8939                         *sp++ = ins;
8940                         break;
8941                 case CEE_LDC_R4: {
8942                         float *f;
8943                         gboolean use_aotconst = FALSE;
8944
8945 #ifdef TARGET_POWERPC
8946                         /* FIXME: Clean this up */
8947                         if (cfg->compile_aot)
8948                                 use_aotconst = TRUE;
8949 #endif
8950
8951                         /* FIXME: we should really allocate this only late in the compilation process */
8952                         f = (float *)mono_domain_alloc (cfg->domain, sizeof (float));
8953                         CHECK_OPSIZE (5);
8954                         CHECK_STACK_OVF (1);
8955
8956                         if (use_aotconst) {
8957                                 MonoInst *cons;
8958                                 int dreg;
8959
8960                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
8961
8962                                 dreg = alloc_freg (cfg);
8963                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
8964                                 ins->type = cfg->r4_stack_type;
8965                         } else {
8966                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
8967                                 ins->type = cfg->r4_stack_type;
8968                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8969                                 ins->inst_p0 = f;
8970                                 MONO_ADD_INS (cfg->cbb, ins);
8971                         }
8972                         ++ip;
8973                         readr4 (ip, f);
8974                         ip += 4;
8975                         *sp++ = ins;                    
8976                         break;
8977                 }
8978                 case CEE_LDC_R8: {
8979                         double *d;
8980                         gboolean use_aotconst = FALSE;
8981
8982 #ifdef TARGET_POWERPC
8983                         /* FIXME: Clean this up */
8984                         if (cfg->compile_aot)
8985                                 use_aotconst = TRUE;
8986 #endif
8987
8988                         /* FIXME: we should really allocate this only late in the compilation process */
8989                         d = (double *)mono_domain_alloc (cfg->domain, sizeof (double));
8990                         CHECK_OPSIZE (9);
8991                         CHECK_STACK_OVF (1);
8992
8993                         if (use_aotconst) {
8994                                 MonoInst *cons;
8995                                 int dreg;
8996
8997                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
8998
8999                                 dreg = alloc_freg (cfg);
9000                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
9001                                 ins->type = STACK_R8;
9002                         } else {
9003                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
9004                                 ins->type = STACK_R8;
9005                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
9006                                 ins->inst_p0 = d;
9007                                 MONO_ADD_INS (cfg->cbb, ins);
9008                         }
9009                         ++ip;
9010                         readr8 (ip, d);
9011                         ip += 8;
9012                         *sp++ = ins;
9013                         break;
9014                 }
9015                 case CEE_DUP: {
9016                         MonoInst *temp, *store;
9017                         CHECK_STACK (1);
9018                         CHECK_STACK_OVF (1);
9019                         sp--;
9020                         ins = *sp;
9021
9022                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
9023                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
9024
9025                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
9026                         *sp++ = ins;
9027
9028                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
9029                         *sp++ = ins;
9030
9031                         ++ip;
9032                         inline_costs += 2;
9033                         break;
9034                 }
9035                 case CEE_POP:
9036                         CHECK_STACK (1);
9037                         ip++;
9038                         --sp;
9039
9040 #ifdef TARGET_X86
9041                         if (sp [0]->type == STACK_R8)
9042                                 /* we need to pop the value from the x86 FP stack */
9043                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
9044 #endif
9045                         break;
9046                 case CEE_JMP: {
9047                         MonoCallInst *call;
9048                         MonoMethodSignature *fsig;
9049                         int i, n;
9050
9051                         INLINE_FAILURE ("jmp");
9052                         GSHAREDVT_FAILURE (*ip);
9053
9054                         CHECK_OPSIZE (5);
9055                         if (stack_start != sp)
9056                                 UNVERIFIED;
9057                         token = read32 (ip + 1);
9058                         /* FIXME: check the signature matches */
9059                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
9060                         CHECK_CFG_ERROR;
9061  
9062                         if (cfg->gshared && mono_method_check_context_used (cmethod))
9063                                 GENERIC_SHARING_FAILURE (CEE_JMP);
9064
9065                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9066
9067                         fsig = mono_method_signature (cmethod);
9068                         n = fsig->param_count + fsig->hasthis;
9069                         if (cfg->llvm_only) {
9070                                 MonoInst **args;
9071
9072                                 args = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
9073                                 for (i = 0; i < n; ++i)
9074                                         EMIT_NEW_ARGLOAD (cfg, args [i], i);
9075                                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, TRUE, args, NULL, NULL, NULL);
9076                                 /*
9077                                  * The code in mono-basic-block.c treats the rest of the code as dead, but we
9078                                  * have to emit a normal return since llvm expects it.
9079                                  */
9080                                 if (cfg->ret)
9081                                         emit_setret (cfg, ins);
9082                                 MONO_INST_NEW (cfg, ins, OP_BR);
9083                                 ins->inst_target_bb = end_bblock;
9084                                 MONO_ADD_INS (cfg->cbb, ins);
9085                                 link_bblock (cfg, cfg->cbb, end_bblock);
9086                                 ip += 5;
9087                                 break;
9088                         } else if (cfg->backend->have_op_tail_call) {
9089                                 /* Handle tail calls similarly to calls */
9090                                 DISABLE_AOT (cfg);
9091
9092                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
9093                                 call->method = cmethod;
9094                                 call->tail_call = TRUE;
9095                                 call->signature = mono_method_signature (cmethod);
9096                                 call->args = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
9097                                 call->inst.inst_p0 = cmethod;
9098                                 for (i = 0; i < n; ++i)
9099                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
9100
9101                                 if (mini_type_is_vtype (mini_get_underlying_type (call->signature->ret)))
9102                                         call->vret_var = cfg->vret_addr;
9103
9104                                 mono_arch_emit_call (cfg, call);
9105                                 cfg->param_area = MAX(cfg->param_area, call->stack_usage);
9106                                 MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
9107                         } else {
9108                                 for (i = 0; i < num_args; ++i)
9109                                         /* Prevent arguments from being optimized away */
9110                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
9111
9112                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9113                                 ins = (MonoInst*)call;
9114                                 ins->inst_p0 = cmethod;
9115                                 MONO_ADD_INS (cfg->cbb, ins);
9116                         }
9117
9118                         ip += 5;
9119                         start_new_bblock = 1;
9120                         break;
9121                 }
9122                 case CEE_CALLI: {
9123                         MonoInst *addr;
9124                         MonoMethodSignature *fsig;
9125
9126                         CHECK_OPSIZE (5);
9127                         token = read32 (ip + 1);
9128
9129                         ins = NULL;
9130
9131                         //GSHAREDVT_FAILURE (*ip);
9132                         cmethod = NULL;
9133                         CHECK_STACK (1);
9134                         --sp;
9135                         addr = *sp;
9136                         fsig = mini_get_signature (method, token, generic_context, &cfg->error);
9137                         CHECK_CFG_ERROR;
9138
9139                         if (method->dynamic && fsig->pinvoke) {
9140                                 MonoInst *args [3];
9141
9142                                 /*
9143                                  * This is a call through a function pointer using a pinvoke
9144                                  * signature. Have to create a wrapper and call that instead.
9145                                  * FIXME: This is very slow, need to create a wrapper at JIT time
9146                                  * instead based on the signature.
9147                                  */
9148                                 EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
9149                                 EMIT_NEW_PCONST (cfg, args [1], fsig);
9150                                 args [2] = addr;
9151                                 addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
9152                         }
9153
9154                         n = fsig->param_count + fsig->hasthis;
9155
9156                         CHECK_STACK (n);
9157
9158                         //g_assert (!virtual_ || fsig->hasthis);
9159
9160                         sp -= n;
9161
9162                         inline_costs += 10 * num_calls++;
9163
9164                         /*
9165                          * Making generic calls out of gsharedvt methods.
9166                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9167                          * patching gshared method addresses into a gsharedvt method.
9168                          */
9169                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
9170                                 /*
9171                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
9172                                  */
9173                                 MonoInst *callee = addr;
9174
9175                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
9176                                         /* Not tested */
9177                                         GSHAREDVT_FAILURE (*ip);
9178
9179                                 if (cfg->llvm_only)
9180                                         // FIXME:
9181                                         GSHAREDVT_FAILURE (*ip);
9182
9183                                 addr = emit_get_rgctx_sig (cfg, context_used,
9184                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
9185                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
9186                                 goto calli_end;
9187                         }
9188
9189                         /* Prevent inlining of methods with indirect calls */
9190                         INLINE_FAILURE ("indirect call");
9191
9192                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
9193                                 MonoJumpInfoType info_type;
9194                                 gpointer info_data;
9195
9196                                 /*
9197                                  * Instead of emitting an indirect call, emit a direct call
9198                                  * with the contents of the aotconst as the patch info.
9199                                  */
9200                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
9201                                         info_type = (MonoJumpInfoType)addr->inst_c1;
9202                                         info_data = addr->inst_p0;
9203                                 } else {
9204                                         info_type = (MonoJumpInfoType)addr->inst_right->inst_c1;
9205                                         info_data = addr->inst_right->inst_left;
9206                                 }
9207
9208                                 if (info_type == MONO_PATCH_INFO_ICALL_ADDR) {
9209                                         ins = (MonoInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_ICALL_ADDR_CALL, info_data, fsig, sp);
9210                                         NULLIFY_INS (addr);
9211                                         goto calli_end;
9212                                 } else if (info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
9213                                         ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
9214                                         NULLIFY_INS (addr);
9215                                         goto calli_end;
9216                                 }
9217                         }
9218                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9219
9220                         calli_end:
9221
9222                         /* End of call, INS should contain the result of the call, if any */
9223
9224                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9225                                 g_assert (ins);
9226                                 *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
9227                         }
9228
9229                         CHECK_CFG_EXCEPTION;
9230
9231                         ip += 5;
9232                         ins_flag = 0;
9233                         constrained_class = NULL;
9234                         break;
9235                 }
9236                 case CEE_CALL:
9237                 case CEE_CALLVIRT: {
9238                         MonoInst *addr = NULL;
9239                         MonoMethodSignature *fsig = NULL;
9240                         int array_rank = 0;
9241                         int virtual_ = *ip == CEE_CALLVIRT;
9242                         gboolean pass_imt_from_rgctx = FALSE;
9243                         MonoInst *imt_arg = NULL;
9244                         MonoInst *keep_this_alive = NULL;
9245                         gboolean pass_vtable = FALSE;
9246                         gboolean pass_mrgctx = FALSE;
9247                         MonoInst *vtable_arg = NULL;
9248                         gboolean check_this = FALSE;
9249                         gboolean supported_tail_call = FALSE;
9250                         gboolean tail_call = FALSE;
9251                         gboolean need_seq_point = FALSE;
9252                         guint32 call_opcode = *ip;
9253                         gboolean emit_widen = TRUE;
9254                         gboolean push_res = TRUE;
9255                         gboolean skip_ret = FALSE;
9256                         gboolean delegate_invoke = FALSE;
9257                         gboolean direct_icall = FALSE;
9258                         gboolean constrained_partial_call = FALSE;
9259                         MonoMethod *cil_method;
9260
9261                         CHECK_OPSIZE (5);
9262                         token = read32 (ip + 1);
9263
9264                         ins = NULL;
9265
9266                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
9267                         CHECK_CFG_ERROR;
9268
9269                         cil_method = cmethod;
9270                                 
9271                         if (constrained_class) {
9272                                 if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
9273                                         if (!mini_is_gsharedvt_klass (constrained_class)) {
9274                                                 g_assert (!cmethod->klass->valuetype);
9275                                                 if (!mini_type_is_reference (&constrained_class->byval_arg))
9276                                                         constrained_partial_call = TRUE;
9277                                         }
9278                                 }
9279
9280                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
9281                                         if (cfg->verbose_level > 2)
9282                                                 printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_class));
9283                                         if (!((constrained_class->byval_arg.type == MONO_TYPE_VAR ||
9284                                                    constrained_class->byval_arg.type == MONO_TYPE_MVAR) &&
9285                                                   cfg->gshared)) {
9286                                                 cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_class, generic_context, &cfg->error);
9287                                                 CHECK_CFG_ERROR;
9288                                         }
9289                                 } else {
9290                                         if (cfg->verbose_level > 2)
9291                                                 printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_class));
9292
9293                                         if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
9294                                                 /* 
9295                                                  * This is needed since get_method_constrained can't find 
9296                                                  * the method in klass representing a type var.
9297                                                  * The type var is guaranteed to be a reference type in this
9298                                                  * case.
9299                                                  */
9300                                                 if (!mini_is_gsharedvt_klass (constrained_class))
9301                                                         g_assert (!cmethod->klass->valuetype);
9302                                         } else {
9303                                                 cmethod = mono_get_method_constrained_checked (image, token, constrained_class, generic_context, &cil_method, &cfg->error);
9304                                                 CHECK_CFG_ERROR;
9305                                         }
9306                                 }
9307                         }
9308                                         
9309                         if (!dont_verify && !cfg->skip_visibility) {
9310                                 MonoMethod *target_method = cil_method;
9311                                 if (method->is_inflated) {
9312                                         target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context), &cfg->error);
9313                                         CHECK_CFG_ERROR;
9314                                 }
9315                                 if (!mono_method_can_access_method (method_definition, target_method) &&
9316                                         !mono_method_can_access_method (method, cil_method))
9317                                         emit_method_access_failure (cfg, method, cil_method);
9318                         }
9319
9320                         if (mono_security_core_clr_enabled ())
9321                                 ensure_method_is_allowed_to_call_method (cfg, method, cil_method);
9322
9323                         if (!virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
9324                                 /* MS.NET seems to silently convert this to a callvirt */
9325                                 virtual_ = 1;
9326
9327                         {
9328                                 /*
9329                                  * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
9330                                  * converts to a callvirt.
9331                                  *
9332                                  * tests/bug-515884.il is an example of this behavior
9333                                  */
9334                                 const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
9335                                 const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
9336                                 if (!virtual_ && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
9337                                         virtual_ = 1;
9338                         }
9339
9340                         if (!cmethod->klass->inited)
9341                                 if (!mono_class_init (cmethod->klass))
9342                                         TYPE_LOAD_ERROR (cmethod->klass);
9343
9344                         fsig = mono_method_signature (cmethod);
9345                         if (!fsig)
9346                                 LOAD_ERROR;
9347                         if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
9348                                 mini_class_is_system_array (cmethod->klass)) {
9349                                 array_rank = cmethod->klass->rank;
9350                         } else if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && icall_is_direct_callable (cfg, cmethod)) {
9351                                 direct_icall = TRUE;
9352                         } else if (fsig->pinvoke) {
9353                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9354                                 fsig = mono_method_signature (wrapper);
9355                         } else if (constrained_class) {
9356                         } else {
9357                                 fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
9358                                 CHECK_CFG_ERROR;
9359                         }
9360
9361                         if (cfg->llvm_only && !cfg->method->wrapper_type && (!cmethod || cmethod->is_inflated))
9362                                 cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
9363
9364                         /* See code below */
9365                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
9366                                 MonoBasicBlock *tbb;
9367
9368                                 GET_BBLOCK (cfg, tbb, ip + 5);
9369                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9370                                         /*
9371                                          * We want to extend the try block to cover the call, but we can't do it if the
9372                                          * call is made directly since its followed by an exception check.
9373                                          */
9374                                         direct_icall = FALSE;
9375                                 }
9376                         }
9377
9378                         mono_save_token_info (cfg, image, token, cil_method);
9379
9380                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip + 5 - header->code)))
9381                                 need_seq_point = TRUE;
9382
9383                         /* Don't support calls made using type arguments for now */
9384                         /*
9385                           if (cfg->gsharedvt) {
9386                           if (mini_is_gsharedvt_signature (fsig))
9387                           GSHAREDVT_FAILURE (*ip);
9388                           }
9389                         */
9390
9391                         if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
9392                                 g_assert_not_reached ();
9393
9394                         n = fsig->param_count + fsig->hasthis;
9395
9396                         if (!cfg->gshared && mono_class_is_gtd (cmethod->klass))
9397                                 UNVERIFIED;
9398
9399                         if (!cfg->gshared)
9400                                 g_assert (!mono_method_check_context_used (cmethod));
9401
9402                         CHECK_STACK (n);
9403
9404                         //g_assert (!virtual_ || fsig->hasthis);
9405
9406                         sp -= n;
9407
9408                         /*
9409                          * We have the `constrained.' prefix opcode.
9410                          */
9411                         if (constrained_class) {
9412                                 if (mini_is_gsharedvt_klass (constrained_class)) {
9413                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_class->valuetype && cmethod->klass->valuetype) {
9414                                                 /* The 'Own method' case below */
9415                                         } else if (cmethod->klass->image != mono_defaults.corlib && !mono_class_is_interface (cmethod->klass) && !cmethod->klass->valuetype) {
9416                                                 /* 'The type parameter is instantiated as a reference type' case below. */
9417                                         } else {
9418                                                 ins = handle_constrained_gsharedvt_call (cfg, cmethod, fsig, sp, constrained_class, &emit_widen);
9419                                                 CHECK_CFG_EXCEPTION;
9420                                                 g_assert (ins);
9421                                                 goto call_end;
9422                                         }
9423                                 }
9424
9425                                 if (constrained_partial_call) {
9426                                         gboolean need_box = TRUE;
9427
9428                                         /*
9429                                          * The receiver is a valuetype, but the exact type is not known at compile time. This means the
9430                                          * called method is not known at compile time either. The called method could end up being
9431                                          * one of the methods on the parent classes (object/valuetype/enum), in which case we need
9432                                          * to box the receiver.
9433                                          * A simple solution would be to box always and make a normal virtual call, but that would
9434                                          * be bad performance wise.
9435                                          */
9436                                         if (mono_class_is_interface (cmethod->klass) && mono_class_is_ginst (cmethod->klass)) {
9437                                                 /*
9438                                                  * The parent classes implement no generic interfaces, so the called method will be a vtype method, so no boxing neccessary.
9439                                                  */
9440                                                 need_box = FALSE;
9441                                         }
9442
9443                                         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)) {
9444                                                 /* The called method is not virtual, i.e. Object:GetType (), the receiver is a vtype, has to box */
9445                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9446                                                 ins->klass = constrained_class;
9447                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9448                                                 CHECK_CFG_EXCEPTION;
9449                                         } else if (need_box) {
9450                                                 MonoInst *box_type;
9451                                                 MonoBasicBlock *is_ref_bb, *end_bb;
9452                                                 MonoInst *nonbox_call;
9453
9454                                                 /*
9455                                                  * Determine at runtime whenever the called method is defined on object/valuetype/enum, and emit a boxing call
9456                                                  * if needed.
9457                                                  * FIXME: It is possible to inline the called method in a lot of cases, i.e. for T_INT,
9458                                                  * the no-box case goes to a method in Int32, while the box case goes to a method in Enum.
9459                                                  */
9460                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
9461
9462                                                 NEW_BBLOCK (cfg, is_ref_bb);
9463                                                 NEW_BBLOCK (cfg, end_bb);
9464
9465                                                 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);
9466                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, box_type->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
9467                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
9468
9469                                                 /* Non-ref case */
9470                                                 nonbox_call = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9471
9472                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9473
9474                                                 /* Ref case */
9475                                                 MONO_START_BB (cfg, is_ref_bb);
9476                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9477                                                 ins->klass = constrained_class;
9478                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9479                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9480
9481                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9482
9483                                                 MONO_START_BB (cfg, end_bb);
9484                                                 cfg->cbb = end_bb;
9485
9486                                                 nonbox_call->dreg = ins->dreg;
9487                                                 goto call_end;
9488                                         } else {
9489                                                 g_assert (mono_class_is_interface (cmethod->klass));
9490                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
9491                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9492                                                 goto call_end;
9493                                         }
9494                                 } else if (constrained_class->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
9495                                         /*
9496                                          * The type parameter is instantiated as a valuetype,
9497                                          * but that type doesn't override the method we're
9498                                          * calling, so we need to box `this'.
9499                                          */
9500                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9501                                         ins->klass = constrained_class;
9502                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9503                                         CHECK_CFG_EXCEPTION;
9504                                 } else if (!constrained_class->valuetype) {
9505                                         int dreg = alloc_ireg_ref (cfg);
9506
9507                                         /*
9508                                          * The type parameter is instantiated as a reference
9509                                          * type.  We have a managed pointer on the stack, so
9510                                          * we need to dereference it here.
9511                                          */
9512                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
9513                                         ins->type = STACK_OBJ;
9514                                         sp [0] = ins;
9515                                 } else {
9516                                         if (cmethod->klass->valuetype) {
9517                                                 /* Own method */
9518                                         } else {
9519                                                 /* Interface method */
9520                                                 int ioffset, slot;
9521
9522                                                 mono_class_setup_vtable (constrained_class);
9523                                                 CHECK_TYPELOAD (constrained_class);
9524                                                 ioffset = mono_class_interface_offset (constrained_class, cmethod->klass);
9525                                                 if (ioffset == -1)
9526                                                         TYPE_LOAD_ERROR (constrained_class);
9527                                                 slot = mono_method_get_vtable_slot (cmethod);
9528                                                 if (slot == -1)
9529                                                         TYPE_LOAD_ERROR (cmethod->klass);
9530                                                 cmethod = constrained_class->vtable [ioffset + slot];
9531
9532                                                 if (cmethod->klass == mono_defaults.enum_class) {
9533                                                         /* Enum implements some interfaces, so treat this as the first case */
9534                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9535                                                         ins->klass = constrained_class;
9536                                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9537                                                         CHECK_CFG_EXCEPTION;
9538                                                 }
9539                                         }
9540                                         virtual_ = 0;
9541                                 }
9542                                 constrained_class = NULL;
9543                         }
9544
9545                         if (check_call_signature (cfg, fsig, sp))
9546                                 UNVERIFIED;
9547
9548                         if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
9549                                 delegate_invoke = TRUE;
9550
9551                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
9552                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9553                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9554                                         emit_widen = FALSE;
9555                                 }
9556
9557                                 goto call_end;
9558                         }
9559
9560                         /* 
9561                          * If the callee is a shared method, then its static cctor
9562                          * might not get called after the call was patched.
9563                          */
9564                         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)) {
9565                                 emit_class_init (cfg, cmethod->klass);
9566                                 CHECK_TYPELOAD (cmethod->klass);
9567                         }
9568
9569                         check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
9570
9571                         if (cfg->gshared) {
9572                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
9573
9574                                 context_used = mini_method_check_context_used (cfg, cmethod);
9575
9576                                 if (context_used && mono_class_is_interface (cmethod->klass)) {
9577                                         /* Generic method interface
9578                                            calls are resolved via a
9579                                            helper function and don't
9580                                            need an imt. */
9581                                         if (!cmethod_context || !cmethod_context->method_inst)
9582                                                 pass_imt_from_rgctx = TRUE;
9583                                 }
9584
9585                                 /*
9586                                  * If a shared method calls another
9587                                  * shared method then the caller must
9588                                  * have a generic sharing context
9589                                  * because the magic trampoline
9590                                  * requires it.  FIXME: We shouldn't
9591                                  * have to force the vtable/mrgctx
9592                                  * variable here.  Instead there
9593                                  * should be a flag in the cfg to
9594                                  * request a generic sharing context.
9595                                  */
9596                                 if (context_used &&
9597                                                 ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
9598                                         mono_get_vtable_var (cfg);
9599                         }
9600
9601                         if (pass_vtable) {
9602                                 if (context_used) {
9603                                         vtable_arg = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
9604                                 } else {
9605                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
9606
9607                                         CHECK_TYPELOAD (cmethod->klass);
9608                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
9609                                 }
9610                         }
9611
9612                         if (pass_mrgctx) {
9613                                 g_assert (!vtable_arg);
9614
9615                                 if (!cfg->compile_aot) {
9616                                         /* 
9617                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
9618                                          * for type load errors before.
9619                                          */
9620                                         mono_class_setup_vtable (cmethod->klass);
9621                                         CHECK_TYPELOAD (cmethod->klass);
9622                                 }
9623
9624                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
9625
9626                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
9627                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
9628                                          MONO_METHOD_IS_FINAL (cmethod)) &&
9629                                         !mono_class_is_marshalbyref (cmethod->klass)) {
9630                                         if (virtual_)
9631                                                 check_this = TRUE;
9632                                         virtual_ = 0;
9633                                 }
9634                         }
9635
9636                         if (pass_imt_from_rgctx) {
9637                                 g_assert (!pass_vtable);
9638
9639                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9640                                         cmethod, MONO_RGCTX_INFO_METHOD);
9641                         }
9642
9643                         if (check_this)
9644                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9645
9646                         /* Calling virtual generic methods */
9647                         if (virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) &&
9648                             !(MONO_METHOD_IS_FINAL (cmethod) && 
9649                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
9650                             fsig->generic_param_count && 
9651                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) &&
9652                                 !cfg->llvm_only) {
9653                                 MonoInst *this_temp, *this_arg_temp, *store;
9654                                 MonoInst *iargs [4];
9655
9656                                 g_assert (fsig->is_inflated);
9657
9658                                 /* Prevent inlining of methods that contain indirect calls */
9659                                 INLINE_FAILURE ("virtual generic call");
9660
9661                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
9662                                         GSHAREDVT_FAILURE (*ip);
9663
9664                                 if (cfg->backend->have_generalized_imt_trampoline && cfg->backend->gshared_supported && cmethod->wrapper_type == MONO_WRAPPER_NONE) {
9665                                         g_assert (!imt_arg);
9666                                         if (!context_used)
9667                                                 g_assert (cmethod->is_inflated);
9668                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
9669                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
9670                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
9671                                 } else {
9672                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
9673                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
9674                                         MONO_ADD_INS (cfg->cbb, store);
9675
9676                                         /* FIXME: This should be a managed pointer */
9677                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
9678
9679                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
9680                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
9681                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
9682                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
9683                                         addr = mono_emit_jit_icall (cfg,
9684                                                                                                 mono_helper_compile_generic_method, iargs);
9685
9686                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
9687
9688                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9689                                 }
9690
9691                                 goto call_end;
9692                         }
9693
9694                         /*
9695                          * Implement a workaround for the inherent races involved in locking:
9696                          * Monitor.Enter ()
9697                          * try {
9698                          * } finally {
9699                          *    Monitor.Exit ()
9700                          * }
9701                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
9702                          * try block, the Exit () won't be executed, see:
9703                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
9704                          * To work around this, we extend such try blocks to include the last x bytes
9705                          * of the Monitor.Enter () call.
9706                          */
9707                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
9708                                 MonoBasicBlock *tbb;
9709
9710                                 GET_BBLOCK (cfg, tbb, ip + 5);
9711                                 /* 
9712                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
9713                                  * from Monitor.Enter like ArgumentNullException.
9714                                  */
9715                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9716                                         /* Mark this bblock as needing to be extended */
9717                                         tbb->extend_try_block = TRUE;
9718                                 }
9719                         }
9720
9721                         /* Conversion to a JIT intrinsic */
9722                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
9723                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9724                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9725                                         emit_widen = FALSE;
9726                                 }
9727                                 goto call_end;
9728                         }
9729                         CHECK_CFG_ERROR;
9730                         
9731                         /* Inlining */
9732                         if ((cfg->opt & MONO_OPT_INLINE) &&
9733                                 (!virtual_ || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
9734                             mono_method_check_inlining (cfg, cmethod)) {
9735                                 int costs;
9736                                 gboolean always = FALSE;
9737
9738                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
9739                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
9740                                         /* Prevent inlining of methods that call wrappers */
9741                                         INLINE_FAILURE ("wrapper call");
9742                                         cmethod = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
9743                                         always = TRUE;
9744                                 }
9745
9746                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, always);
9747                                 if (costs) {
9748                                         cfg->real_offset += 5;
9749
9750                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9751                                                 /* *sp is already set by inline_method */
9752                                                 sp++;
9753                                                 push_res = FALSE;
9754                                         }
9755
9756                                         inline_costs += costs;
9757
9758                                         goto call_end;
9759                                 }
9760                         }
9761
9762                         /* Tail recursion elimination */
9763                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
9764                                 gboolean has_vtargs = FALSE;
9765                                 int i;
9766
9767                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9768                                 INLINE_FAILURE ("tail call");
9769
9770                                 /* keep it simple */
9771                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
9772                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
9773                                                 has_vtargs = TRUE;
9774                                 }
9775
9776                                 if (!has_vtargs) {
9777                                         if (need_seq_point) {
9778                                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
9779                                                 need_seq_point = FALSE;
9780                                         }
9781                                         for (i = 0; i < n; ++i)
9782                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9783                                         MONO_INST_NEW (cfg, ins, OP_BR);
9784                                         MONO_ADD_INS (cfg->cbb, ins);
9785                                         tblock = start_bblock->out_bb [0];
9786                                         link_bblock (cfg, cfg->cbb, tblock);
9787                                         ins->inst_target_bb = tblock;
9788                                         start_new_bblock = 1;
9789
9790                                         /* skip the CEE_RET, too */
9791                                         if (ip_in_bb (cfg, cfg->cbb, ip + 5))
9792                                                 skip_ret = TRUE;
9793                                         push_res = FALSE;
9794                                         goto call_end;
9795                                 }
9796                         }
9797
9798                         inline_costs += 10 * num_calls++;
9799
9800                         /*
9801                          * Synchronized wrappers.
9802                          * Its hard to determine where to replace a method with its synchronized
9803                          * wrapper without causing an infinite recursion. The current solution is
9804                          * to add the synchronized wrapper in the trampolines, and to
9805                          * change the called method to a dummy wrapper, and resolve that wrapper
9806                          * to the real method in mono_jit_compile_method ().
9807                          */
9808                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
9809                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
9810                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
9811                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
9812                         }
9813
9814                         /*
9815                          * Making generic calls out of gsharedvt methods.
9816                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9817                          * patching gshared method addresses into a gsharedvt method.
9818                          */
9819                         if (cfg->gsharedvt && (mini_is_gsharedvt_signature (fsig) || cmethod->is_inflated || mono_class_is_ginst (cmethod->klass)) &&
9820                                 !(cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY) &&
9821                                 (!(cfg->llvm_only && virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)))) {
9822                                 MonoRgctxInfoType info_type;
9823
9824                                 if (virtual_) {
9825                                         //if (mono_class_is_interface (cmethod->klass))
9826                                                 //GSHAREDVT_FAILURE (*ip);
9827                                         // disable for possible remoting calls
9828                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
9829                                                 GSHAREDVT_FAILURE (*ip);
9830                                         if (fsig->generic_param_count) {
9831                                                 /* virtual generic call */
9832                                                 g_assert (!imt_arg);
9833                                                 /* Same as the virtual generic case above */
9834                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9835                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9836                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
9837                                                 vtable_arg = NULL;
9838                                         } else if (mono_class_is_interface (cmethod->klass) && !imt_arg) {
9839                                                 /* This can happen when we call a fully instantiated iface method */
9840                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9841                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9842                                                 vtable_arg = NULL;
9843                                         }
9844                                 }
9845
9846                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
9847                                         keep_this_alive = sp [0];
9848
9849                                 if (virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
9850                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
9851                                 else
9852                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
9853                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
9854
9855                                 if (cfg->llvm_only) {
9856                                         // FIXME: Avoid initializing vtable_arg
9857                                         ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
9858                                 } else {
9859                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9860                                 }
9861                                 goto call_end;
9862                         }
9863
9864                         /* Generic sharing */
9865
9866                         /*
9867                          * Use this if the callee is gsharedvt sharable too, since
9868                          * at runtime we might find an instantiation so the call cannot
9869                          * be patched (the 'no_patch' code path in mini-trampolines.c).
9870                          */
9871                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
9872                                 (!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
9873                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
9874                                 (!virtual_ || MONO_METHOD_IS_FINAL (cmethod) ||
9875                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
9876                                 INLINE_FAILURE ("gshared");
9877
9878                                 g_assert (cfg->gshared && cmethod);
9879                                 g_assert (!addr);
9880
9881                                 /*
9882                                  * We are compiling a call to a
9883                                  * generic method from shared code,
9884                                  * which means that we have to look up
9885                                  * the method in the rgctx and do an
9886                                  * indirect call.
9887                                  */
9888                                 if (fsig->hasthis)
9889                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9890
9891                                 if (cfg->llvm_only) {
9892                                         if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig))
9893                                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER);
9894                                         else
9895                                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9896                                         // FIXME: Avoid initializing imt_arg/vtable_arg
9897                                         ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
9898                                 } else {
9899                                         addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9900                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9901                                 }
9902                                 goto call_end;
9903                         }
9904
9905                         /* Direct calls to icalls */
9906                         if (direct_icall) {
9907                                 MonoMethod *wrapper;
9908                                 int costs;
9909
9910                                 /* Inline the wrapper */
9911                                 wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9912
9913                                 costs = inline_method (cfg, wrapper, fsig, sp, ip, cfg->real_offset, TRUE);
9914                                 g_assert (costs > 0);
9915                                 cfg->real_offset += 5;
9916
9917                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9918                                         /* *sp is already set by inline_method */
9919                                         sp++;
9920                                         push_res = FALSE;
9921                                 }
9922
9923                                 inline_costs += costs;
9924
9925                                 goto call_end;
9926                         }
9927                                         
9928                         /* Array methods */
9929                         if (array_rank) {
9930                                 MonoInst *addr;
9931
9932                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
9933                                         MonoInst *val = sp [fsig->param_count];
9934
9935                                         if (val->type == STACK_OBJ) {
9936                                                 MonoInst *iargs [2];
9937
9938                                                 iargs [0] = sp [0];
9939                                                 iargs [1] = val;
9940                                                 
9941                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
9942                                         }
9943                                         
9944                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
9945                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
9946                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !MONO_INS_IS_PCONST_NULL (val))
9947                                                 emit_write_barrier (cfg, addr, val);
9948                                         if (cfg->gen_write_barriers && mini_is_gsharedvt_klass (cmethod->klass))
9949                                                 GSHAREDVT_FAILURE (*ip);
9950                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
9951                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9952
9953                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
9954                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
9955                                         if (!cmethod->klass->element_class->valuetype && !readonly)
9956                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
9957                                         CHECK_TYPELOAD (cmethod->klass);
9958                                         
9959                                         readonly = FALSE;
9960                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9961                                         ins = addr;
9962                                 } else {
9963                                         g_assert_not_reached ();
9964                                 }
9965
9966                                 emit_widen = FALSE;
9967                                 goto call_end;
9968                         }
9969
9970                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual_ ? sp [0] : NULL);
9971                         if (ins)
9972                                 goto call_end;
9973
9974                         /* Tail prefix / tail call optimization */
9975
9976                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
9977                         /* FIXME: runtime generic context pointer for jumps? */
9978                         /* FIXME: handle this for generic sharing eventually */
9979                         if ((ins_flag & MONO_INST_TAILCALL) &&
9980                                 !vtable_arg && !cfg->gshared && is_supported_tail_call (cfg, method, cmethod, fsig, call_opcode))
9981                                 supported_tail_call = TRUE;
9982
9983                         if (supported_tail_call) {
9984                                 MonoCallInst *call;
9985
9986                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9987                                 INLINE_FAILURE ("tail call");
9988
9989                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
9990
9991                                 if (cfg->backend->have_op_tail_call) {
9992                                         /* Handle tail calls similarly to normal calls */
9993                                         tail_call = TRUE;
9994                                 } else {
9995                                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9996
9997                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9998                                         call->tail_call = TRUE;
9999                                         call->method = cmethod;
10000                                         call->signature = mono_method_signature (cmethod);
10001
10002                                         /*
10003                                          * We implement tail calls by storing the actual arguments into the 
10004                                          * argument variables, then emitting a CEE_JMP.
10005                                          */
10006                                         for (i = 0; i < n; ++i) {
10007                                                 /* Prevent argument from being register allocated */
10008                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
10009                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
10010                                         }
10011                                         ins = (MonoInst*)call;
10012                                         ins->inst_p0 = cmethod;
10013                                         ins->inst_p1 = arg_array [0];
10014                                         MONO_ADD_INS (cfg->cbb, ins);
10015                                         link_bblock (cfg, cfg->cbb, end_bblock);
10016                                         start_new_bblock = 1;
10017
10018                                         // FIXME: Eliminate unreachable epilogs
10019
10020                                         /*
10021                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
10022                                          * only reachable from this call.
10023                                          */
10024                                         GET_BBLOCK (cfg, tblock, ip + 5);
10025                                         if (tblock == cfg->cbb || tblock->in_count == 0)
10026                                                 skip_ret = TRUE;
10027                                         push_res = FALSE;
10028
10029                                         goto call_end;
10030                                 }
10031                         }
10032
10033                         /*
10034                          * Virtual calls in llvm-only mode.
10035                          */
10036                         if (cfg->llvm_only && virtual_ && cmethod && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
10037                                 ins = emit_llvmonly_virtual_call (cfg, cmethod, fsig, context_used, sp);
10038                                 goto call_end;
10039                         }
10040
10041                         /* Common call */
10042                         if (!(cmethod->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
10043                                 INLINE_FAILURE ("call");
10044                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual_ ? sp [0] : NULL,
10045                                                                                           imt_arg, vtable_arg);
10046
10047                         if (tail_call && !cfg->llvm_only) {
10048                                 link_bblock (cfg, cfg->cbb, end_bblock);
10049                                 start_new_bblock = 1;
10050
10051                                 // FIXME: Eliminate unreachable epilogs
10052
10053                                 /*
10054                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
10055                                  * only reachable from this call.
10056                                  */
10057                                 GET_BBLOCK (cfg, tblock, ip + 5);
10058                                 if (tblock == cfg->cbb || tblock->in_count == 0)
10059                                         skip_ret = TRUE;
10060                                 push_res = FALSE;
10061                         }
10062
10063                         call_end:
10064
10065                         /* End of call, INS should contain the result of the call, if any */
10066
10067                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
10068                                 g_assert (ins);
10069                                 if (emit_widen)
10070                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
10071                                 else
10072                                         *sp++ = ins;
10073                         }
10074
10075                         if (keep_this_alive) {
10076                                 MonoInst *dummy_use;
10077
10078                                 /* See mono_emit_method_call_full () */
10079                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
10080                         }
10081
10082                         if (cfg->llvm_only && cmethod && method_needs_stack_walk (cfg, cmethod)) {
10083                                 /*
10084                                  * Clang can convert these calls to tail calls which screw up the stack
10085                                  * walk. This happens even when the -fno-optimize-sibling-calls
10086                                  * option is passed to clang.
10087                                  * Work around this by emitting a dummy call.
10088                                  */
10089                                 mono_emit_jit_icall (cfg, mono_dummy_jit_icall, NULL);
10090                         }
10091
10092                         CHECK_CFG_EXCEPTION;
10093
10094                         ip += 5;
10095                         if (skip_ret) {
10096                                 g_assert (*ip == CEE_RET);
10097                                 ip += 1;
10098                         }
10099                         ins_flag = 0;
10100                         constrained_class = NULL;
10101                         if (need_seq_point)
10102                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10103                         break;
10104                 }
10105                 case CEE_RET:
10106                         if (cfg->method != method) {
10107                                 /* return from inlined method */
10108                                 /* 
10109                                  * If in_count == 0, that means the ret is unreachable due to
10110                                  * being preceeded by a throw. In that case, inline_method () will
10111                                  * handle setting the return value 
10112                                  * (test case: test_0_inline_throw ()).
10113                                  */
10114                                 if (return_var && cfg->cbb->in_count) {
10115                                         MonoType *ret_type = mono_method_signature (method)->ret;
10116
10117                                         MonoInst *store;
10118                                         CHECK_STACK (1);
10119                                         --sp;
10120
10121                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
10122                                                 UNVERIFIED;
10123
10124                                         //g_assert (returnvar != -1);
10125                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
10126                                         cfg->ret_var_set = TRUE;
10127                                 } 
10128                         } else {
10129                                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
10130
10131                                 if (cfg->lmf_var && cfg->cbb->in_count && !cfg->llvm_only)
10132                                         emit_pop_lmf (cfg);
10133
10134                                 if (cfg->ret) {
10135                                         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (method)->ret);
10136
10137                                         if (seq_points && !sym_seq_points) {
10138                                                 /* 
10139                                                  * Place a seq point here too even through the IL stack is not
10140                                                  * empty, so a step over on
10141                                                  * call <FOO>
10142                                                  * ret
10143                                                  * will work correctly.
10144                                                  */
10145                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
10146                                                 MONO_ADD_INS (cfg->cbb, ins);
10147                                         }
10148
10149                                         g_assert (!return_var);
10150                                         CHECK_STACK (1);
10151                                         --sp;
10152
10153                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
10154                                                 UNVERIFIED;
10155
10156                                         emit_setret (cfg, *sp);
10157                                 }
10158                         }
10159                         if (sp != stack_start)
10160                                 UNVERIFIED;
10161                         MONO_INST_NEW (cfg, ins, OP_BR);
10162                         ip++;
10163                         ins->inst_target_bb = end_bblock;
10164                         MONO_ADD_INS (cfg->cbb, ins);
10165                         link_bblock (cfg, cfg->cbb, end_bblock);
10166                         start_new_bblock = 1;
10167                         break;
10168                 case CEE_BR_S:
10169                         CHECK_OPSIZE (2);
10170                         MONO_INST_NEW (cfg, ins, OP_BR);
10171                         ip++;
10172                         target = ip + 1 + (signed char)(*ip);
10173                         ++ip;
10174                         GET_BBLOCK (cfg, tblock, target);
10175                         link_bblock (cfg, cfg->cbb, tblock);
10176                         ins->inst_target_bb = tblock;
10177                         if (sp != stack_start) {
10178                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10179                                 sp = stack_start;
10180                                 CHECK_UNVERIFIABLE (cfg);
10181                         }
10182                         MONO_ADD_INS (cfg->cbb, ins);
10183                         start_new_bblock = 1;
10184                         inline_costs += BRANCH_COST;
10185                         break;
10186                 case CEE_BEQ_S:
10187                 case CEE_BGE_S:
10188                 case CEE_BGT_S:
10189                 case CEE_BLE_S:
10190                 case CEE_BLT_S:
10191                 case CEE_BNE_UN_S:
10192                 case CEE_BGE_UN_S:
10193                 case CEE_BGT_UN_S:
10194                 case CEE_BLE_UN_S:
10195                 case CEE_BLT_UN_S:
10196                         CHECK_OPSIZE (2);
10197                         CHECK_STACK (2);
10198                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
10199                         ip++;
10200                         target = ip + 1 + *(signed char*)ip;
10201                         ip++;
10202
10203                         ADD_BINCOND (NULL);
10204
10205                         sp = stack_start;
10206                         inline_costs += BRANCH_COST;
10207                         break;
10208                 case CEE_BR:
10209                         CHECK_OPSIZE (5);
10210                         MONO_INST_NEW (cfg, ins, OP_BR);
10211                         ip++;
10212
10213                         target = ip + 4 + (gint32)read32(ip);
10214                         ip += 4;
10215                         GET_BBLOCK (cfg, tblock, target);
10216                         link_bblock (cfg, cfg->cbb, tblock);
10217                         ins->inst_target_bb = tblock;
10218                         if (sp != stack_start) {
10219                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10220                                 sp = stack_start;
10221                                 CHECK_UNVERIFIABLE (cfg);
10222                         }
10223
10224                         MONO_ADD_INS (cfg->cbb, ins);
10225
10226                         start_new_bblock = 1;
10227                         inline_costs += BRANCH_COST;
10228                         break;
10229                 case CEE_BRFALSE_S:
10230                 case CEE_BRTRUE_S:
10231                 case CEE_BRFALSE:
10232                 case CEE_BRTRUE: {
10233                         MonoInst *cmp;
10234                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
10235                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
10236                         guint32 opsize = is_short ? 1 : 4;
10237
10238                         CHECK_OPSIZE (opsize);
10239                         CHECK_STACK (1);
10240                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
10241                                 UNVERIFIED;
10242                         ip ++;
10243                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
10244                         ip += opsize;
10245
10246                         sp--;
10247
10248                         GET_BBLOCK (cfg, tblock, target);
10249                         link_bblock (cfg, cfg->cbb, tblock);
10250                         GET_BBLOCK (cfg, tblock, ip);
10251                         link_bblock (cfg, cfg->cbb, tblock);
10252
10253                         if (sp != stack_start) {
10254                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10255                                 CHECK_UNVERIFIABLE (cfg);
10256                         }
10257
10258                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
10259                         cmp->sreg1 = sp [0]->dreg;
10260                         type_from_op (cfg, cmp, sp [0], NULL);
10261                         CHECK_TYPE (cmp);
10262
10263 #if SIZEOF_REGISTER == 4
10264                         if (cmp->opcode == OP_LCOMPARE_IMM) {
10265                                 /* Convert it to OP_LCOMPARE */
10266                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
10267                                 ins->type = STACK_I8;
10268                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
10269                                 ins->inst_l = 0;
10270                                 MONO_ADD_INS (cfg->cbb, ins);
10271                                 cmp->opcode = OP_LCOMPARE;
10272                                 cmp->sreg2 = ins->dreg;
10273                         }
10274 #endif
10275                         MONO_ADD_INS (cfg->cbb, cmp);
10276
10277                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
10278                         type_from_op (cfg, ins, sp [0], NULL);
10279                         MONO_ADD_INS (cfg->cbb, ins);
10280                         ins->inst_many_bb = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
10281                         GET_BBLOCK (cfg, tblock, target);
10282                         ins->inst_true_bb = tblock;
10283                         GET_BBLOCK (cfg, tblock, ip);
10284                         ins->inst_false_bb = tblock;
10285                         start_new_bblock = 2;
10286
10287                         sp = stack_start;
10288                         inline_costs += BRANCH_COST;
10289                         break;
10290                 }
10291                 case CEE_BEQ:
10292                 case CEE_BGE:
10293                 case CEE_BGT:
10294                 case CEE_BLE:
10295                 case CEE_BLT:
10296                 case CEE_BNE_UN:
10297                 case CEE_BGE_UN:
10298                 case CEE_BGT_UN:
10299                 case CEE_BLE_UN:
10300                 case CEE_BLT_UN:
10301                         CHECK_OPSIZE (5);
10302                         CHECK_STACK (2);
10303                         MONO_INST_NEW (cfg, ins, *ip);
10304                         ip++;
10305                         target = ip + 4 + (gint32)read32(ip);
10306                         ip += 4;
10307
10308                         ADD_BINCOND (NULL);
10309
10310                         sp = stack_start;
10311                         inline_costs += BRANCH_COST;
10312                         break;
10313                 case CEE_SWITCH: {
10314                         MonoInst *src1;
10315                         MonoBasicBlock **targets;
10316                         MonoBasicBlock *default_bblock;
10317                         MonoJumpInfoBBTable *table;
10318                         int offset_reg = alloc_preg (cfg);
10319                         int target_reg = alloc_preg (cfg);
10320                         int table_reg = alloc_preg (cfg);
10321                         int sum_reg = alloc_preg (cfg);
10322                         gboolean use_op_switch;
10323
10324                         CHECK_OPSIZE (5);
10325                         CHECK_STACK (1);
10326                         n = read32 (ip + 1);
10327                         --sp;
10328                         src1 = sp [0];
10329                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
10330                                 UNVERIFIED;
10331
10332                         ip += 5;
10333                         CHECK_OPSIZE (n * sizeof (guint32));
10334                         target = ip + n * sizeof (guint32);
10335
10336                         GET_BBLOCK (cfg, default_bblock, target);
10337                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
10338
10339                         targets = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
10340                         for (i = 0; i < n; ++i) {
10341                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
10342                                 targets [i] = tblock;
10343                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
10344                                 ip += 4;
10345                         }
10346
10347                         if (sp != stack_start) {
10348                                 /* 
10349                                  * Link the current bb with the targets as well, so handle_stack_args
10350                                  * will set their in_stack correctly.
10351                                  */
10352                                 link_bblock (cfg, cfg->cbb, default_bblock);
10353                                 for (i = 0; i < n; ++i)
10354                                         link_bblock (cfg, cfg->cbb, targets [i]);
10355
10356                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10357                                 sp = stack_start;
10358                                 CHECK_UNVERIFIABLE (cfg);
10359
10360                                 /* Undo the links */
10361                                 mono_unlink_bblock (cfg, cfg->cbb, default_bblock);
10362                                 for (i = 0; i < n; ++i)
10363                                         mono_unlink_bblock (cfg, cfg->cbb, targets [i]);
10364                         }
10365
10366                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
10367                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
10368
10369                         for (i = 0; i < n; ++i)
10370                                 link_bblock (cfg, cfg->cbb, targets [i]);
10371
10372                         table = (MonoJumpInfoBBTable *)mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
10373                         table->table = targets;
10374                         table->table_size = n;
10375
10376                         use_op_switch = FALSE;
10377 #ifdef TARGET_ARM
10378                         /* ARM implements SWITCH statements differently */
10379                         /* FIXME: Make it use the generic implementation */
10380                         if (!cfg->compile_aot)
10381                                 use_op_switch = TRUE;
10382 #endif
10383
10384                         if (COMPILE_LLVM (cfg))
10385                                 use_op_switch = TRUE;
10386
10387                         cfg->cbb->has_jump_table = 1;
10388
10389                         if (use_op_switch) {
10390                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
10391                                 ins->sreg1 = src1->dreg;
10392                                 ins->inst_p0 = table;
10393                                 ins->inst_many_bb = targets;
10394                                 ins->klass = (MonoClass *)GUINT_TO_POINTER (n);
10395                                 MONO_ADD_INS (cfg->cbb, ins);
10396                         } else {
10397                                 if (sizeof (gpointer) == 8)
10398                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
10399                                 else
10400                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
10401
10402 #if SIZEOF_REGISTER == 8
10403                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
10404                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
10405 #endif
10406
10407                                 if (cfg->compile_aot) {
10408                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
10409                                 } else {
10410                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
10411                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
10412                                         ins->inst_p0 = table;
10413                                         ins->dreg = table_reg;
10414                                         MONO_ADD_INS (cfg->cbb, ins);
10415                                 }
10416
10417                                 /* FIXME: Use load_memindex */
10418                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
10419                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
10420                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
10421                         }
10422                         start_new_bblock = 1;
10423                         inline_costs += (BRANCH_COST * 2);
10424                         break;
10425                 }
10426                 case CEE_LDIND_I1:
10427                 case CEE_LDIND_U1:
10428                 case CEE_LDIND_I2:
10429                 case CEE_LDIND_U2:
10430                 case CEE_LDIND_I4:
10431                 case CEE_LDIND_U4:
10432                 case CEE_LDIND_I8:
10433                 case CEE_LDIND_I:
10434                 case CEE_LDIND_R4:
10435                 case CEE_LDIND_R8:
10436                 case CEE_LDIND_REF:
10437                         CHECK_STACK (1);
10438                         --sp;
10439
10440                         switch (*ip) {
10441                         case CEE_LDIND_R4:
10442                         case CEE_LDIND_R8:
10443                                 dreg = alloc_freg (cfg);
10444                                 break;
10445                         case CEE_LDIND_I8:
10446                                 dreg = alloc_lreg (cfg);
10447                                 break;
10448                         case CEE_LDIND_REF:
10449                                 dreg = alloc_ireg_ref (cfg);
10450                                 break;
10451                         default:
10452                                 dreg = alloc_preg (cfg);
10453                         }
10454
10455                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
10456                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
10457                         if (*ip == CEE_LDIND_R4)
10458                                 ins->type = cfg->r4_stack_type;
10459                         ins->flags |= ins_flag;
10460                         MONO_ADD_INS (cfg->cbb, ins);
10461                         *sp++ = ins;
10462                         if (ins_flag & MONO_INST_VOLATILE) {
10463                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10464                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10465                         }
10466                         ins_flag = 0;
10467                         ++ip;
10468                         break;
10469                 case CEE_STIND_REF:
10470                 case CEE_STIND_I1:
10471                 case CEE_STIND_I2:
10472                 case CEE_STIND_I4:
10473                 case CEE_STIND_I8:
10474                 case CEE_STIND_R4:
10475                 case CEE_STIND_R8:
10476                 case CEE_STIND_I:
10477                         CHECK_STACK (2);
10478                         sp -= 2;
10479
10480                         if (ins_flag & MONO_INST_VOLATILE) {
10481                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
10482                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
10483                         }
10484
10485                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
10486                         ins->flags |= ins_flag;
10487                         ins_flag = 0;
10488
10489                         MONO_ADD_INS (cfg->cbb, ins);
10490
10491                         if (cfg->gen_write_barriers && *ip == CEE_STIND_REF && method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER && !MONO_INS_IS_PCONST_NULL (sp [1]))
10492                                 emit_write_barrier (cfg, sp [0], sp [1]);
10493
10494                         inline_costs += 1;
10495                         ++ip;
10496                         break;
10497
10498                 case CEE_MUL:
10499                         CHECK_STACK (2);
10500
10501                         MONO_INST_NEW (cfg, ins, (*ip));
10502                         sp -= 2;
10503                         ins->sreg1 = sp [0]->dreg;
10504                         ins->sreg2 = sp [1]->dreg;
10505                         type_from_op (cfg, ins, sp [0], sp [1]);
10506                         CHECK_TYPE (ins);
10507                         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type);
10508
10509                         /* Use the immediate opcodes if possible */
10510                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
10511                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
10512                                 if (imm_opcode != -1) {
10513                                         ins->opcode = imm_opcode;
10514                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
10515                                         ins->sreg2 = -1;
10516
10517                                         NULLIFY_INS (sp [1]);
10518                                 }
10519                         }
10520
10521                         MONO_ADD_INS ((cfg)->cbb, (ins));
10522
10523                         *sp++ = mono_decompose_opcode (cfg, ins);
10524                         ip++;
10525                         break;
10526                 case CEE_ADD:
10527                 case CEE_SUB:
10528                 case CEE_DIV:
10529                 case CEE_DIV_UN:
10530                 case CEE_REM:
10531                 case CEE_REM_UN:
10532                 case CEE_AND:
10533                 case CEE_OR:
10534                 case CEE_XOR:
10535                 case CEE_SHL:
10536                 case CEE_SHR:
10537                 case CEE_SHR_UN:
10538                         CHECK_STACK (2);
10539
10540                         MONO_INST_NEW (cfg, ins, (*ip));
10541                         sp -= 2;
10542                         ins->sreg1 = sp [0]->dreg;
10543                         ins->sreg2 = sp [1]->dreg;
10544                         type_from_op (cfg, ins, sp [0], sp [1]);
10545                         CHECK_TYPE (ins);
10546                         add_widen_op (cfg, ins, &sp [0], &sp [1]);
10547                         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type);
10548
10549                         /* FIXME: Pass opcode to is_inst_imm */
10550
10551                         /* Use the immediate opcodes if possible */
10552                         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)) {
10553                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
10554                                 if (imm_opcode != -1) {
10555                                         ins->opcode = imm_opcode;
10556                                         if (sp [1]->opcode == OP_I8CONST) {
10557 #if SIZEOF_REGISTER == 8
10558                                                 ins->inst_imm = sp [1]->inst_l;
10559 #else
10560                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
10561                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
10562 #endif
10563                                         }
10564                                         else
10565                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
10566                                         ins->sreg2 = -1;
10567
10568                                         /* Might be followed by an instruction added by add_widen_op */
10569                                         if (sp [1]->next == NULL)
10570                                                 NULLIFY_INS (sp [1]);
10571                                 }
10572                         }
10573                         MONO_ADD_INS ((cfg)->cbb, (ins));
10574
10575                         *sp++ = mono_decompose_opcode (cfg, ins);
10576                         ip++;
10577                         break;
10578                 case CEE_NEG:
10579                 case CEE_NOT:
10580                 case CEE_CONV_I1:
10581                 case CEE_CONV_I2:
10582                 case CEE_CONV_I4:
10583                 case CEE_CONV_R4:
10584                 case CEE_CONV_R8:
10585                 case CEE_CONV_U4:
10586                 case CEE_CONV_I8:
10587                 case CEE_CONV_U8:
10588                 case CEE_CONV_OVF_I8:
10589                 case CEE_CONV_OVF_U8:
10590                 case CEE_CONV_R_UN:
10591                         CHECK_STACK (1);
10592
10593                         /* Special case this earlier so we have long constants in the IR */
10594                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
10595                                 int data = sp [-1]->inst_c0;
10596                                 sp [-1]->opcode = OP_I8CONST;
10597                                 sp [-1]->type = STACK_I8;
10598 #if SIZEOF_REGISTER == 8
10599                                 if ((*ip) == CEE_CONV_U8)
10600                                         sp [-1]->inst_c0 = (guint32)data;
10601                                 else
10602                                         sp [-1]->inst_c0 = data;
10603 #else
10604                                 sp [-1]->inst_ls_word = data;
10605                                 if ((*ip) == CEE_CONV_U8)
10606                                         sp [-1]->inst_ms_word = 0;
10607                                 else
10608                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
10609 #endif
10610                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
10611                         }
10612                         else {
10613                                 ADD_UNOP (*ip);
10614                         }
10615                         ip++;
10616                         break;
10617                 case CEE_CONV_OVF_I4:
10618                 case CEE_CONV_OVF_I1:
10619                 case CEE_CONV_OVF_I2:
10620                 case CEE_CONV_OVF_I:
10621                 case CEE_CONV_OVF_U:
10622                         CHECK_STACK (1);
10623
10624                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10625                                 ADD_UNOP (CEE_CONV_OVF_I8);
10626                                 ADD_UNOP (*ip);
10627                         } else {
10628                                 ADD_UNOP (*ip);
10629                         }
10630                         ip++;
10631                         break;
10632                 case CEE_CONV_OVF_U1:
10633                 case CEE_CONV_OVF_U2:
10634                 case CEE_CONV_OVF_U4:
10635                         CHECK_STACK (1);
10636
10637                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10638                                 ADD_UNOP (CEE_CONV_OVF_U8);
10639                                 ADD_UNOP (*ip);
10640                         } else {
10641                                 ADD_UNOP (*ip);
10642                         }
10643                         ip++;
10644                         break;
10645                 case CEE_CONV_OVF_I1_UN:
10646                 case CEE_CONV_OVF_I2_UN:
10647                 case CEE_CONV_OVF_I4_UN:
10648                 case CEE_CONV_OVF_I8_UN:
10649                 case CEE_CONV_OVF_U1_UN:
10650                 case CEE_CONV_OVF_U2_UN:
10651                 case CEE_CONV_OVF_U4_UN:
10652                 case CEE_CONV_OVF_U8_UN:
10653                 case CEE_CONV_OVF_I_UN:
10654                 case CEE_CONV_OVF_U_UN:
10655                 case CEE_CONV_U2:
10656                 case CEE_CONV_U1:
10657                 case CEE_CONV_I:
10658                 case CEE_CONV_U:
10659                         CHECK_STACK (1);
10660                         ADD_UNOP (*ip);
10661                         CHECK_CFG_EXCEPTION;
10662                         ip++;
10663                         break;
10664                 case CEE_ADD_OVF:
10665                 case CEE_ADD_OVF_UN:
10666                 case CEE_MUL_OVF:
10667                 case CEE_MUL_OVF_UN:
10668                 case CEE_SUB_OVF:
10669                 case CEE_SUB_OVF_UN:
10670                         CHECK_STACK (2);
10671                         ADD_BINOP (*ip);
10672                         ip++;
10673                         break;
10674                 case CEE_CPOBJ:
10675                         GSHAREDVT_FAILURE (*ip);
10676                         CHECK_OPSIZE (5);
10677                         CHECK_STACK (2);
10678                         token = read32 (ip + 1);
10679                         klass = mini_get_class (method, token, generic_context);
10680                         CHECK_TYPELOAD (klass);
10681                         sp -= 2;
10682                         if (generic_class_is_reference_type (cfg, klass)) {
10683                                 MonoInst *store, *load;
10684                                 int dreg = alloc_ireg_ref (cfg);
10685
10686                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
10687                                 load->flags |= ins_flag;
10688                                 MONO_ADD_INS (cfg->cbb, load);
10689
10690                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
10691                                 store->flags |= ins_flag;
10692                                 MONO_ADD_INS (cfg->cbb, store);
10693
10694                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
10695                                         emit_write_barrier (cfg, sp [0], sp [1]);
10696                         } else {
10697                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10698                         }
10699                         ins_flag = 0;
10700                         ip += 5;
10701                         break;
10702                 case CEE_LDOBJ: {
10703                         int loc_index = -1;
10704                         int stloc_len = 0;
10705
10706                         CHECK_OPSIZE (5);
10707                         CHECK_STACK (1);
10708                         --sp;
10709                         token = read32 (ip + 1);
10710                         klass = mini_get_class (method, token, generic_context);
10711                         CHECK_TYPELOAD (klass);
10712
10713                         /* Optimize the common ldobj+stloc combination */
10714                         switch (ip [5]) {
10715                         case CEE_STLOC_S:
10716                                 loc_index = ip [6];
10717                                 stloc_len = 2;
10718                                 break;
10719                         case CEE_STLOC_0:
10720                         case CEE_STLOC_1:
10721                         case CEE_STLOC_2:
10722                         case CEE_STLOC_3:
10723                                 loc_index = ip [5] - CEE_STLOC_0;
10724                                 stloc_len = 1;
10725                                 break;
10726                         default:
10727                                 break;
10728                         }
10729
10730                         if ((loc_index != -1) && ip_in_bb (cfg, cfg->cbb, ip + 5)) {
10731                                 CHECK_LOCAL (loc_index);
10732
10733                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10734                                 ins->dreg = cfg->locals [loc_index]->dreg;
10735                                 ins->flags |= ins_flag;
10736                                 ip += 5;
10737                                 ip += stloc_len;
10738                                 if (ins_flag & MONO_INST_VOLATILE) {
10739                                         /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10740                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10741                                 }
10742                                 ins_flag = 0;
10743                                 break;
10744                         }
10745
10746                         /* Optimize the ldobj+stobj combination */
10747                         /* The reference case ends up being a load+store anyway */
10748                         /* Skip this if the operation is volatile. */
10749                         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)) {
10750                                 CHECK_STACK (1);
10751
10752                                 sp --;
10753
10754                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10755
10756                                 ip += 5 + 5;
10757                                 ins_flag = 0;
10758                                 break;
10759                         }
10760
10761                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10762                         ins->flags |= ins_flag;
10763                         *sp++ = ins;
10764
10765                         if (ins_flag & MONO_INST_VOLATILE) {
10766                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10767                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10768                         }
10769
10770                         ip += 5;
10771                         ins_flag = 0;
10772                         inline_costs += 1;
10773                         break;
10774                 }
10775                 case CEE_LDSTR:
10776                         CHECK_STACK_OVF (1);
10777                         CHECK_OPSIZE (5);
10778                         n = read32 (ip + 1);
10779
10780                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
10781                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
10782                                 ins->type = STACK_OBJ;
10783                                 *sp = ins;
10784                         }
10785                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
10786                                 MonoInst *iargs [1];
10787                                 char *str = (char *)mono_method_get_wrapper_data (method, n);
10788
10789                                 if (cfg->compile_aot)
10790                                         EMIT_NEW_LDSTRLITCONST (cfg, iargs [0], str);
10791                                 else
10792                                         EMIT_NEW_PCONST (cfg, iargs [0], str);
10793                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
10794                         } else {
10795                                 if (cfg->opt & MONO_OPT_SHARED) {
10796                                         MonoInst *iargs [3];
10797
10798                                         if (cfg->compile_aot) {
10799                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
10800                                         }
10801                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10802                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
10803                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
10804                                         *sp = mono_emit_jit_icall (cfg, ves_icall_mono_ldstr, iargs);
10805                                         mono_ldstr_checked (cfg->domain, image, mono_metadata_token_index (n), &cfg->error);
10806                                         CHECK_CFG_ERROR;
10807                                 } else {
10808                                         if (cfg->cbb->out_of_line) {
10809                                                 MonoInst *iargs [2];
10810
10811                                                 if (image == mono_defaults.corlib) {
10812                                                         /* 
10813                                                          * Avoid relocations in AOT and save some space by using a 
10814                                                          * version of helper_ldstr specialized to mscorlib.
10815                                                          */
10816                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
10817                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
10818                                                 } else {
10819                                                         /* Avoid creating the string object */
10820                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
10821                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
10822                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
10823                                                 }
10824                                         } 
10825                                         else
10826                                         if (cfg->compile_aot) {
10827                                                 NEW_LDSTRCONST (cfg, ins, image, n);
10828                                                 *sp = ins;
10829                                                 MONO_ADD_INS (cfg->cbb, ins);
10830                                         } 
10831                                         else {
10832                                                 NEW_PCONST (cfg, ins, NULL);
10833                                                 ins->type = STACK_OBJ;
10834                                                 ins->inst_p0 = mono_ldstr_checked (cfg->domain, image, mono_metadata_token_index (n), &cfg->error);
10835                                                 CHECK_CFG_ERROR;
10836                                                 
10837                                                 if (!ins->inst_p0)
10838                                                         OUT_OF_MEMORY_FAILURE;
10839
10840                                                 *sp = ins;
10841                                                 MONO_ADD_INS (cfg->cbb, ins);
10842                                         }
10843                                 }
10844                         }
10845
10846                         sp++;
10847                         ip += 5;
10848                         break;
10849                 case CEE_NEWOBJ: {
10850                         MonoInst *iargs [2];
10851                         MonoMethodSignature *fsig;
10852                         MonoInst this_ins;
10853                         MonoInst *alloc;
10854                         MonoInst *vtable_arg = NULL;
10855
10856                         CHECK_OPSIZE (5);
10857                         token = read32 (ip + 1);
10858                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
10859                         CHECK_CFG_ERROR;
10860
10861                         fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
10862                         CHECK_CFG_ERROR;
10863
10864                         mono_save_token_info (cfg, image, token, cmethod);
10865
10866                         if (!mono_class_init (cmethod->klass))
10867                                 TYPE_LOAD_ERROR (cmethod->klass);
10868
10869                         context_used = mini_method_check_context_used (cfg, cmethod);
10870
10871                         if (mono_security_core_clr_enabled ())
10872                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
10873
10874                         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)) {
10875                                 emit_class_init (cfg, cmethod->klass);
10876                                 CHECK_TYPELOAD (cmethod->klass);
10877                         }
10878
10879                         /*
10880                         if (cfg->gsharedvt) {
10881                                 if (mini_is_gsharedvt_variable_signature (sig))
10882                                         GSHAREDVT_FAILURE (*ip);
10883                         }
10884                         */
10885
10886                         n = fsig->param_count;
10887                         CHECK_STACK (n);
10888
10889                         /* 
10890                          * Generate smaller code for the common newobj <exception> instruction in
10891                          * argument checking code.
10892                          */
10893                         if (cfg->cbb->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
10894                                 is_exception_class (cmethod->klass) && n <= 2 &&
10895                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
10896                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
10897                                 MonoInst *iargs [3];
10898
10899                                 sp -= n;
10900
10901                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
10902                                 switch (n) {
10903                                 case 0:
10904                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
10905                                         break;
10906                                 case 1:
10907                                         iargs [1] = sp [0];
10908                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
10909                                         break;
10910                                 case 2:
10911                                         iargs [1] = sp [0];
10912                                         iargs [2] = sp [1];
10913                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
10914                                         break;
10915                                 default:
10916                                         g_assert_not_reached ();
10917                                 }
10918
10919                                 ip += 5;
10920                                 inline_costs += 5;
10921                                 break;
10922                         }
10923
10924                         /* move the args to allow room for 'this' in the first position */
10925                         while (n--) {
10926                                 --sp;
10927                                 sp [1] = sp [0];
10928                         }
10929
10930                         /* check_call_signature () requires sp[0] to be set */
10931                         this_ins.type = STACK_OBJ;
10932                         sp [0] = &this_ins;
10933                         if (check_call_signature (cfg, fsig, sp))
10934                                 UNVERIFIED;
10935
10936                         iargs [0] = NULL;
10937
10938                         if (mini_class_is_system_array (cmethod->klass)) {
10939                                 *sp = emit_get_rgctx_method (cfg, context_used,
10940                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
10941
10942                                 /* Avoid varargs in the common case */
10943                                 if (fsig->param_count == 1)
10944                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
10945                                 else if (fsig->param_count == 2)
10946                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
10947                                 else if (fsig->param_count == 3)
10948                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
10949                                 else if (fsig->param_count == 4)
10950                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
10951                                 else
10952                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
10953                         } else if (cmethod->string_ctor) {
10954                                 g_assert (!context_used);
10955                                 g_assert (!vtable_arg);
10956                                 /* we simply pass a null pointer */
10957                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
10958                                 /* now call the string ctor */
10959                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
10960                         } else {
10961                                 if (cmethod->klass->valuetype) {
10962                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
10963                                         emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
10964                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
10965
10966                                         alloc = NULL;
10967
10968                                         /* 
10969                                          * The code generated by mini_emit_virtual_call () expects
10970                                          * iargs [0] to be a boxed instance, but luckily the vcall
10971                                          * will be transformed into a normal call there.
10972                                          */
10973                                 } else if (context_used) {
10974                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
10975                                         *sp = alloc;
10976                                 } else {
10977                                         MonoVTable *vtable = NULL;
10978
10979                                         if (!cfg->compile_aot)
10980                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
10981                                         CHECK_TYPELOAD (cmethod->klass);
10982
10983                                         /*
10984                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
10985                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
10986                                          * As a workaround, we call class cctors before allocating objects.
10987                                          */
10988                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
10989                                                 emit_class_init (cfg, cmethod->klass);
10990                                                 if (cfg->verbose_level > 2)
10991                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
10992                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
10993                                         }
10994
10995                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
10996                                         *sp = alloc;
10997                                 }
10998                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
10999
11000                                 if (alloc)
11001                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
11002
11003                                 /* Now call the actual ctor */
11004                                 handle_ctor_call (cfg, cmethod, fsig, context_used, sp, ip, &inline_costs);
11005                                 CHECK_CFG_EXCEPTION;
11006                         }
11007
11008                         if (alloc == NULL) {
11009                                 /* Valuetype */
11010                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
11011                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
11012                                 *sp++= ins;
11013                         } else {
11014                                 *sp++ = alloc;
11015                         }
11016                         
11017                         ip += 5;
11018                         inline_costs += 5;
11019                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip - header->code)))
11020                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
11021                         break;
11022                 }
11023                 case CEE_CASTCLASS:
11024                 case CEE_ISINST: {
11025                         CHECK_STACK (1);
11026                         --sp;
11027                         CHECK_OPSIZE (5);
11028                         token = read32 (ip + 1);
11029                         klass = mini_get_class (method, token, generic_context);
11030                         CHECK_TYPELOAD (klass);
11031                         if (sp [0]->type != STACK_OBJ)
11032                                 UNVERIFIED;
11033
11034                         MONO_INST_NEW (cfg, ins, *ip == CEE_ISINST ? OP_ISINST : OP_CASTCLASS);
11035                         ins->dreg = alloc_preg (cfg);
11036                         ins->sreg1 = (*sp)->dreg;
11037                         ins->klass = klass;
11038                         ins->type = STACK_OBJ;
11039                         MONO_ADD_INS (cfg->cbb, ins);
11040
11041                         CHECK_CFG_EXCEPTION;
11042                         *sp++ = ins;
11043                         ip += 5;
11044
11045                         cfg->flags |= MONO_CFG_HAS_TYPE_CHECK;
11046                         break;
11047                 }
11048                 case CEE_UNBOX_ANY: {
11049                         MonoInst *res, *addr;
11050
11051                         CHECK_STACK (1);
11052                         --sp;
11053                         CHECK_OPSIZE (5);
11054                         token = read32 (ip + 1);
11055                         klass = mini_get_class (method, token, generic_context);
11056                         CHECK_TYPELOAD (klass);
11057
11058                         mono_save_token_info (cfg, image, token, klass);
11059
11060                         context_used = mini_class_check_context_used (cfg, klass);
11061
11062                         if (mini_is_gsharedvt_klass (klass)) {
11063                                 res = handle_unbox_gsharedvt (cfg, klass, *sp);
11064                                 inline_costs += 2;
11065                         } else if (generic_class_is_reference_type (cfg, klass)) {
11066                                 if (MONO_INS_IS_PCONST_NULL (*sp)) {
11067                                         EMIT_NEW_PCONST (cfg, res, NULL);
11068                                         res->type = STACK_OBJ;
11069                                 } else {
11070                                         MONO_INST_NEW (cfg, res, OP_CASTCLASS);
11071                                         res->dreg = alloc_preg (cfg);
11072                                         res->sreg1 = (*sp)->dreg;
11073                                         res->klass = klass;
11074                                         res->type = STACK_OBJ;
11075                                         MONO_ADD_INS (cfg->cbb, res);
11076                                         cfg->flags |= MONO_CFG_HAS_TYPE_CHECK;
11077                                 }
11078                         } else if (mono_class_is_nullable (klass)) {
11079                                 res = handle_unbox_nullable (cfg, *sp, klass, context_used);
11080                         } else {
11081                                 addr = handle_unbox (cfg, klass, sp, context_used);
11082                                 /* LDOBJ */
11083                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11084                                 res = ins;
11085                                 inline_costs += 2;
11086                         }
11087
11088                         *sp ++ = res;
11089                         ip += 5;
11090                         break;
11091                 }
11092                 case CEE_BOX: {
11093                         MonoInst *val;
11094                         MonoClass *enum_class;
11095                         MonoMethod *has_flag;
11096
11097                         CHECK_STACK (1);
11098                         --sp;
11099                         val = *sp;
11100                         CHECK_OPSIZE (5);
11101                         token = read32 (ip + 1);
11102                         klass = mini_get_class (method, token, generic_context);
11103                         CHECK_TYPELOAD (klass);
11104
11105                         mono_save_token_info (cfg, image, token, klass);
11106
11107                         context_used = mini_class_check_context_used (cfg, klass);
11108
11109                         if (generic_class_is_reference_type (cfg, klass)) {
11110                                 *sp++ = val;
11111                                 ip += 5;
11112                                 break;
11113                         }
11114
11115                         if (klass == mono_defaults.void_class)
11116                                 UNVERIFIED;
11117                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
11118                                 UNVERIFIED;
11119                         /* frequent check in generic code: box (struct), brtrue */
11120
11121                         /*
11122                          * Look for:
11123                          *
11124                          *   <push int/long ptr>
11125                          *   <push int/long>
11126                          *   box MyFlags
11127                          *   constrained. MyFlags
11128                          *   callvirt instace bool class [mscorlib] System.Enum::HasFlag (class [mscorlib] System.Enum)
11129                          *
11130                          * If we find this sequence and the operand types on box and constrained
11131                          * are equal, we can emit a specialized instruction sequence instead of
11132                          * the very slow HasFlag () call.
11133                          */
11134                         if ((cfg->opt & MONO_OPT_INTRINS) &&
11135                             /* Cheap checks first. */
11136                             ip + 5 + 6 + 5 < end &&
11137                             ip [5] == CEE_PREFIX1 &&
11138                             ip [6] == CEE_CONSTRAINED_ &&
11139                             ip [11] == CEE_CALLVIRT &&
11140                             ip_in_bb (cfg, cfg->cbb, ip + 5 + 6 + 5) &&
11141                             mono_class_is_enum (klass) &&
11142                             (enum_class = mini_get_class (method, read32 (ip + 7), generic_context)) &&
11143                             (has_flag = mini_get_method (cfg, method, read32 (ip + 12), NULL, generic_context)) &&
11144                             has_flag->klass == mono_defaults.enum_class &&
11145                             !strcmp (has_flag->name, "HasFlag") &&
11146                             has_flag->signature->hasthis &&
11147                             has_flag->signature->param_count == 1) {
11148                                 CHECK_TYPELOAD (enum_class);
11149
11150                                 if (enum_class == klass) {
11151                                         MonoInst *enum_this, *enum_flag;
11152
11153                                         ip += 5 + 6 + 5;
11154                                         --sp;
11155
11156                                         enum_this = sp [0];
11157                                         enum_flag = sp [1];
11158
11159                                         *sp++ = handle_enum_has_flag (cfg, klass, enum_this, enum_flag);
11160                                         break;
11161                                 }
11162                         }
11163
11164                         // FIXME: LLVM can't handle the inconsistent bb linking
11165                         if (!mono_class_is_nullable (klass) &&
11166                                 !mini_is_gsharedvt_klass (klass) &&
11167                                 ip + 5 < end && ip_in_bb (cfg, cfg->cbb, ip + 5) &&
11168                                 (ip [5] == CEE_BRTRUE || 
11169                                  ip [5] == CEE_BRTRUE_S ||
11170                                  ip [5] == CEE_BRFALSE ||
11171                                  ip [5] == CEE_BRFALSE_S)) {
11172                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
11173                                 int dreg;
11174                                 MonoBasicBlock *true_bb, *false_bb;
11175
11176                                 ip += 5;
11177
11178                                 if (cfg->verbose_level > 3) {
11179                                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
11180                                         printf ("<box+brtrue opt>\n");
11181                                 }
11182
11183                                 switch (*ip) {
11184                                 case CEE_BRTRUE_S:
11185                                 case CEE_BRFALSE_S:
11186                                         CHECK_OPSIZE (2);
11187                                         ip++;
11188                                         target = ip + 1 + (signed char)(*ip);
11189                                         ip++;
11190                                         break;
11191                                 case CEE_BRTRUE:
11192                                 case CEE_BRFALSE:
11193                                         CHECK_OPSIZE (5);
11194                                         ip++;
11195                                         target = ip + 4 + (gint)(read32 (ip));
11196                                         ip += 4;
11197                                         break;
11198                                 default:
11199                                         g_assert_not_reached ();
11200                                 }
11201
11202                                 /* 
11203                                  * We need to link both bblocks, since it is needed for handling stack
11204                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
11205                                  * Branching to only one of them would lead to inconsistencies, so
11206                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
11207                                  */
11208                                 GET_BBLOCK (cfg, true_bb, target);
11209                                 GET_BBLOCK (cfg, false_bb, ip);
11210
11211                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
11212                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
11213
11214                                 if (sp != stack_start) {
11215                                         handle_stack_args (cfg, stack_start, sp - stack_start);
11216                                         sp = stack_start;
11217                                         CHECK_UNVERIFIABLE (cfg);
11218                                 }
11219
11220                                 if (COMPILE_LLVM (cfg)) {
11221                                         dreg = alloc_ireg (cfg);
11222                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
11223                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
11224
11225                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
11226                                 } else {
11227                                         /* The JIT can't eliminate the iconst+compare */
11228                                         MONO_INST_NEW (cfg, ins, OP_BR);
11229                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
11230                                         MONO_ADD_INS (cfg->cbb, ins);
11231                                 }
11232
11233                                 start_new_bblock = 1;
11234                                 break;
11235                         }
11236
11237                         *sp++ = handle_box (cfg, val, klass, context_used);
11238
11239                         CHECK_CFG_EXCEPTION;
11240                         ip += 5;
11241                         inline_costs += 1;
11242                         break;
11243                 }
11244                 case CEE_UNBOX: {
11245                         CHECK_STACK (1);
11246                         --sp;
11247                         CHECK_OPSIZE (5);
11248                         token = read32 (ip + 1);
11249                         klass = mini_get_class (method, token, generic_context);
11250                         CHECK_TYPELOAD (klass);
11251
11252                         mono_save_token_info (cfg, image, token, klass);
11253
11254                         context_used = mini_class_check_context_used (cfg, klass);
11255
11256                         if (mono_class_is_nullable (klass)) {
11257                                 MonoInst *val;
11258
11259                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
11260                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
11261
11262                                 *sp++= ins;
11263                         } else {
11264                                 ins = handle_unbox (cfg, klass, sp, context_used);
11265                                 *sp++ = ins;
11266                         }
11267                         ip += 5;
11268                         inline_costs += 2;
11269                         break;
11270                 }
11271                 case CEE_LDFLD:
11272                 case CEE_LDFLDA:
11273                 case CEE_STFLD:
11274                 case CEE_LDSFLD:
11275                 case CEE_LDSFLDA:
11276                 case CEE_STSFLD: {
11277                         MonoClassField *field;
11278 #ifndef DISABLE_REMOTING
11279                         int costs;
11280 #endif
11281                         guint foffset;
11282                         gboolean is_instance;
11283                         int op;
11284                         gpointer addr = NULL;
11285                         gboolean is_special_static;
11286                         MonoType *ftype;
11287                         MonoInst *store_val = NULL;
11288                         MonoInst *thread_ins;
11289
11290                         op = *ip;
11291                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
11292                         if (is_instance) {
11293                                 if (op == CEE_STFLD) {
11294                                         CHECK_STACK (2);
11295                                         sp -= 2;
11296                                         store_val = sp [1];
11297                                 } else {
11298                                         CHECK_STACK (1);
11299                                         --sp;
11300                                 }
11301                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
11302                                         UNVERIFIED;
11303                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
11304                                         UNVERIFIED;
11305                         } else {
11306                                 if (op == CEE_STSFLD) {
11307                                         CHECK_STACK (1);
11308                                         sp--;
11309                                         store_val = sp [0];
11310                                 }
11311                         }
11312
11313                         CHECK_OPSIZE (5);
11314                         token = read32 (ip + 1);
11315                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
11316                                 field = (MonoClassField *)mono_method_get_wrapper_data (method, token);
11317                                 klass = field->parent;
11318                         }
11319                         else {
11320                                 field = mono_field_from_token_checked (image, token, &klass, generic_context, &cfg->error);
11321                                 CHECK_CFG_ERROR;
11322                         }
11323                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
11324                                 FIELD_ACCESS_FAILURE (method, field);
11325                         mono_class_init (klass);
11326
11327                         /* if the class is Critical then transparent code cannot access it's fields */
11328                         if (!is_instance && mono_security_core_clr_enabled ())
11329                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
11330
11331                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
11332                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
11333                         if (mono_security_core_clr_enabled ())
11334                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
11335                         */
11336
11337                         ftype = mono_field_get_type (field);
11338
11339                         /*
11340                          * LDFLD etc. is usable on static fields as well, so convert those cases to
11341                          * the static case.
11342                          */
11343                         if (is_instance && ftype->attrs & FIELD_ATTRIBUTE_STATIC) {
11344                                 switch (op) {
11345                                 case CEE_LDFLD:
11346                                         op = CEE_LDSFLD;
11347                                         break;
11348                                 case CEE_STFLD:
11349                                         op = CEE_STSFLD;
11350                                         break;
11351                                 case CEE_LDFLDA:
11352                                         op = CEE_LDSFLDA;
11353                                         break;
11354                                 default:
11355                                         g_assert_not_reached ();
11356                                 }
11357                                 is_instance = FALSE;
11358                         }
11359
11360                         context_used = mini_class_check_context_used (cfg, klass);
11361
11362                         /* INSTANCE CASE */
11363
11364                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
11365                         if (op == CEE_STFLD) {
11366                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
11367                                         UNVERIFIED;
11368 #ifndef DISABLE_REMOTING
11369                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
11370                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
11371                                         MonoInst *iargs [5];
11372
11373                                         GSHAREDVT_FAILURE (op);
11374
11375                                         iargs [0] = sp [0];
11376                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11377                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
11378                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
11379                                                     field->offset);
11380                                         iargs [4] = sp [1];
11381
11382                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
11383                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
11384                                                                                            iargs, ip, cfg->real_offset, TRUE);
11385                                                 CHECK_CFG_EXCEPTION;
11386                                                 g_assert (costs > 0);
11387                                                       
11388                                                 cfg->real_offset += 5;
11389
11390                                                 inline_costs += costs;
11391                                         } else {
11392                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
11393                                         }
11394                                 } else
11395 #endif
11396                                 {
11397                                         MonoInst *store, *wbarrier_ptr_ins = NULL;
11398
11399                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
11400
11401                                         if (ins_flag & MONO_INST_VOLATILE) {
11402                                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11403                                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11404                                         }
11405
11406                                         if (mini_is_gsharedvt_klass (klass)) {
11407                                                 MonoInst *offset_ins;
11408
11409                                                 context_used = mini_class_check_context_used (cfg, klass);
11410
11411                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11412                                                 /* The value is offset by 1 */
11413                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11414                                                 dreg = alloc_ireg_mp (cfg);
11415                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11416                                                 wbarrier_ptr_ins = ins;
11417                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
11418                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
11419                                         } else {
11420                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
11421                                         }
11422                                         if (sp [0]->opcode != OP_LDADDR)
11423                                                 store->flags |= MONO_INST_FAULT;
11424
11425                                         if (cfg->gen_write_barriers && mini_type_to_stind (cfg, field->type) == CEE_STIND_REF && !MONO_INS_IS_PCONST_NULL (sp [1])) {
11426                                                 if (mini_is_gsharedvt_klass (klass)) {
11427                                                         g_assert (wbarrier_ptr_ins);
11428                                                         emit_write_barrier (cfg, wbarrier_ptr_ins, sp [1]);
11429                                                 } else {
11430                                                         /* insert call to write barrier */
11431                                                         MonoInst *ptr;
11432                                                         int dreg;
11433
11434                                                         dreg = alloc_ireg_mp (cfg);
11435                                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
11436                                                         emit_write_barrier (cfg, ptr, sp [1]);
11437                                                 }
11438                                         }
11439
11440                                         store->flags |= ins_flag;
11441                                 }
11442                                 ins_flag = 0;
11443                                 ip += 5;
11444                                 break;
11445                         }
11446
11447 #ifndef DISABLE_REMOTING
11448                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
11449                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
11450                                 MonoInst *iargs [4];
11451
11452                                 GSHAREDVT_FAILURE (op);
11453
11454                                 iargs [0] = sp [0];
11455                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11456                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
11457                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
11458                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
11459                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
11460                                                                                    iargs, ip, cfg->real_offset, TRUE);
11461                                         CHECK_CFG_EXCEPTION;
11462                                         g_assert (costs > 0);
11463                                                       
11464                                         cfg->real_offset += 5;
11465
11466                                         *sp++ = iargs [0];
11467
11468                                         inline_costs += costs;
11469                                 } else {
11470                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
11471                                         *sp++ = ins;
11472                                 }
11473                         } else 
11474 #endif
11475                         if (is_instance) {
11476                                 if (sp [0]->type == STACK_VTYPE) {
11477                                         MonoInst *var;
11478
11479                                         /* Have to compute the address of the variable */
11480
11481                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
11482                                         if (!var)
11483                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
11484                                         else
11485                                                 g_assert (var->klass == klass);
11486                                         
11487                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
11488                                         sp [0] = ins;
11489                                 }
11490
11491                                 if (op == CEE_LDFLDA) {
11492                                         if (sp [0]->type == STACK_OBJ) {
11493                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
11494                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
11495                                         }
11496
11497                                         dreg = alloc_ireg_mp (cfg);
11498
11499                                         if (mini_is_gsharedvt_klass (klass)) {
11500                                                 MonoInst *offset_ins;
11501
11502                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11503                                                 /* The value is offset by 1 */
11504                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11505                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11506                                         } else {
11507                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
11508                                         }
11509                                         ins->klass = mono_class_from_mono_type (field->type);
11510                                         ins->type = STACK_MP;
11511                                         *sp++ = ins;
11512                                 } else {
11513                                         MonoInst *load;
11514
11515                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
11516
11517                                         if (sp [0]->opcode == OP_LDADDR && klass->simd_type && cfg->opt & MONO_OPT_SIMD) {
11518                                                 ins = mono_emit_simd_field_load (cfg, field, sp [0]);
11519                                                 if (ins) {
11520                                                         *sp++ = ins;
11521                                                         ins_flag = 0;
11522                                                         ip += 5;
11523                                                         break;
11524                                                 }
11525                                         }
11526
11527                                         if (mini_is_gsharedvt_klass (klass)) {
11528                                                 MonoInst *offset_ins;
11529
11530                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11531                                                 /* The value is offset by 1 */
11532                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11533                                                 dreg = alloc_ireg_mp (cfg);
11534                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11535                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
11536                                         } else {
11537                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
11538                                         }
11539                                         load->flags |= ins_flag;
11540                                         if (sp [0]->opcode != OP_LDADDR)
11541                                                 load->flags |= MONO_INST_FAULT;
11542                                         *sp++ = load;
11543                                 }
11544                         }
11545
11546                         if (is_instance) {
11547                                 ins_flag = 0;
11548                                 ip += 5;
11549                                 break;
11550                         }
11551
11552                         /* STATIC CASE */
11553                         context_used = mini_class_check_context_used (cfg, klass);
11554
11555                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL) {
11556                                 mono_error_set_field_load (&cfg->error, field->parent, field->name, "Using static instructions with literal field");
11557                                 CHECK_CFG_ERROR;
11558                         }
11559
11560                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
11561                          * to be called here.
11562                          */
11563                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
11564                                 mono_class_vtable (cfg->domain, klass);
11565                                 CHECK_TYPELOAD (klass);
11566                         }
11567                         mono_domain_lock (cfg->domain);
11568                         if (cfg->domain->special_static_fields)
11569                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
11570                         mono_domain_unlock (cfg->domain);
11571
11572                         is_special_static = mono_class_field_is_special_static (field);
11573
11574                         if (is_special_static && ((gsize)addr & 0x80000000) == 0)
11575                                 thread_ins = mono_get_thread_intrinsic (cfg);
11576                         else
11577                                 thread_ins = NULL;
11578
11579                         /* Generate IR to compute the field address */
11580                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
11581                                 /*
11582                                  * Fast access to TLS data
11583                                  * Inline version of get_thread_static_data () in
11584                                  * threads.c.
11585                                  */
11586                                 guint32 offset;
11587                                 int idx, static_data_reg, array_reg, dreg;
11588
11589                                 GSHAREDVT_FAILURE (op);
11590
11591                                 MONO_ADD_INS (cfg->cbb, thread_ins);
11592                                 static_data_reg = alloc_ireg (cfg);
11593                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
11594
11595                                 if (cfg->compile_aot) {
11596                                         int offset_reg, offset2_reg, idx_reg;
11597
11598                                         /* For TLS variables, this will return the TLS offset */
11599                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
11600                                         offset_reg = ins->dreg;
11601                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
11602                                         idx_reg = alloc_ireg (cfg);
11603                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, idx_reg, offset_reg, 0x3f);
11604                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
11605                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
11606                                         array_reg = alloc_ireg (cfg);
11607                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
11608                                         offset2_reg = alloc_ireg (cfg);
11609                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, offset2_reg, offset_reg, 6);
11610                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset2_reg, 0x1ffffff);
11611                                         dreg = alloc_ireg (cfg);
11612                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
11613                                 } else {
11614                                         offset = (gsize)addr & 0x7fffffff;
11615                                         idx = offset & 0x3f;
11616
11617                                         array_reg = alloc_ireg (cfg);
11618                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
11619                                         dreg = alloc_ireg (cfg);
11620                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, ((offset >> 6) & 0x1ffffff));
11621                                 }
11622                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
11623                                         (cfg->compile_aot && is_special_static) ||
11624                                         (context_used && is_special_static)) {
11625                                 MonoInst *iargs [2];
11626
11627                                 g_assert (field->parent);
11628                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11629                                 if (context_used) {
11630                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
11631                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
11632                                 } else {
11633                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11634                                 }
11635                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11636                         } else if (context_used) {
11637                                 MonoInst *static_data;
11638
11639                                 /*
11640                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
11641                                         method->klass->name_space, method->klass->name, method->name,
11642                                         depth, field->offset);
11643                                 */
11644
11645                                 if (mono_class_needs_cctor_run (klass, method))
11646                                         emit_class_init (cfg, klass);
11647
11648                                 /*
11649                                  * The pointer we're computing here is
11650                                  *
11651                                  *   super_info.static_data + field->offset
11652                                  */
11653                                 static_data = emit_get_rgctx_klass (cfg, context_used,
11654                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
11655
11656                                 if (mini_is_gsharedvt_klass (klass)) {
11657                                         MonoInst *offset_ins;
11658
11659                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11660                                         /* The value is offset by 1 */
11661                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11662                                         dreg = alloc_ireg_mp (cfg);
11663                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
11664                                 } else if (field->offset == 0) {
11665                                         ins = static_data;
11666                                 } else {
11667                                         int addr_reg = mono_alloc_preg (cfg);
11668                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
11669                                 }
11670                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
11671                                 MonoInst *iargs [2];
11672
11673                                 g_assert (field->parent);
11674                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11675                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11676                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11677                         } else {
11678                                 MonoVTable *vtable = NULL;
11679
11680                                 if (!cfg->compile_aot)
11681                                         vtable = mono_class_vtable (cfg->domain, klass);
11682                                 CHECK_TYPELOAD (klass);
11683
11684                                 if (!addr) {
11685                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
11686                                                 if (!(g_slist_find (class_inits, klass))) {
11687                                                         emit_class_init (cfg, klass);
11688                                                         if (cfg->verbose_level > 2)
11689                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
11690                                                         class_inits = g_slist_prepend (class_inits, klass);
11691                                                 }
11692                                         } else {
11693                                                 if (cfg->run_cctors) {
11694                                                         /* This makes so that inline cannot trigger */
11695                                                         /* .cctors: too many apps depend on them */
11696                                                         /* running with a specific order... */
11697                                                         g_assert (vtable);
11698                                                         if (! vtable->initialized)
11699                                                                 INLINE_FAILURE ("class init");
11700                                                         if (!mono_runtime_class_init_full (vtable, &cfg->error)) {
11701                                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
11702                                                                 goto exception_exit;
11703                                                         }
11704                                                 }
11705                                         }
11706                                         if (cfg->compile_aot)
11707                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
11708                                         else {
11709                                                 g_assert (vtable);
11710                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11711                                                 g_assert (addr);
11712                                                 EMIT_NEW_PCONST (cfg, ins, addr);
11713                                         }
11714                                 } else {
11715                                         MonoInst *iargs [1];
11716                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
11717                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
11718                                 }
11719                         }
11720
11721                         /* Generate IR to do the actual load/store operation */
11722
11723                         if ((op == CEE_STFLD || op == CEE_STSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11724                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11725                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11726                         }
11727
11728                         if (op == CEE_LDSFLDA) {
11729                                 ins->klass = mono_class_from_mono_type (ftype);
11730                                 ins->type = STACK_PTR;
11731                                 *sp++ = ins;
11732                         } else if (op == CEE_STSFLD) {
11733                                 MonoInst *store;
11734
11735                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
11736                                 store->flags |= ins_flag;
11737                         } else {
11738                                 gboolean is_const = FALSE;
11739                                 MonoVTable *vtable = NULL;
11740                                 gpointer addr = NULL;
11741
11742                                 if (!context_used) {
11743                                         vtable = mono_class_vtable (cfg->domain, klass);
11744                                         CHECK_TYPELOAD (klass);
11745                                 }
11746                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
11747                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
11748                                         int ro_type = ftype->type;
11749                                         if (!addr)
11750                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11751                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
11752                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
11753                                         }
11754
11755                                         GSHAREDVT_FAILURE (op);
11756
11757                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
11758                                         is_const = TRUE;
11759                                         switch (ro_type) {
11760                                         case MONO_TYPE_BOOLEAN:
11761                                         case MONO_TYPE_U1:
11762                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
11763                                                 sp++;
11764                                                 break;
11765                                         case MONO_TYPE_I1:
11766                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
11767                                                 sp++;
11768                                                 break;                                          
11769                                         case MONO_TYPE_CHAR:
11770                                         case MONO_TYPE_U2:
11771                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
11772                                                 sp++;
11773                                                 break;
11774                                         case MONO_TYPE_I2:
11775                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
11776                                                 sp++;
11777                                                 break;
11778                                                 break;
11779                                         case MONO_TYPE_I4:
11780                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
11781                                                 sp++;
11782                                                 break;                                          
11783                                         case MONO_TYPE_U4:
11784                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
11785                                                 sp++;
11786                                                 break;
11787                                         case MONO_TYPE_I:
11788                                         case MONO_TYPE_U:
11789                                         case MONO_TYPE_PTR:
11790                                         case MONO_TYPE_FNPTR:
11791                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11792                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
11793                                                 sp++;
11794                                                 break;
11795                                         case MONO_TYPE_STRING:
11796                                         case MONO_TYPE_OBJECT:
11797                                         case MONO_TYPE_CLASS:
11798                                         case MONO_TYPE_SZARRAY:
11799                                         case MONO_TYPE_ARRAY:
11800                                                 if (!mono_gc_is_moving ()) {
11801                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11802                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
11803                                                         sp++;
11804                                                 } else {
11805                                                         is_const = FALSE;
11806                                                 }
11807                                                 break;
11808                                         case MONO_TYPE_I8:
11809                                         case MONO_TYPE_U8:
11810                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
11811                                                 sp++;
11812                                                 break;
11813                                         case MONO_TYPE_R4:
11814                                         case MONO_TYPE_R8:
11815                                         case MONO_TYPE_VALUETYPE:
11816                                         default:
11817                                                 is_const = FALSE;
11818                                                 break;
11819                                         }
11820                                 }
11821
11822                                 if (!is_const) {
11823                                         MonoInst *load;
11824
11825                                         CHECK_STACK_OVF (1);
11826
11827                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
11828                                         load->flags |= ins_flag;
11829                                         ins_flag = 0;
11830                                         *sp++ = load;
11831                                 }
11832                         }
11833
11834                         if ((op == CEE_LDFLD || op == CEE_LDSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11835                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
11836                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
11837                         }
11838
11839                         ins_flag = 0;
11840                         ip += 5;
11841                         break;
11842                 }
11843                 case CEE_STOBJ:
11844                         CHECK_STACK (2);
11845                         sp -= 2;
11846                         CHECK_OPSIZE (5);
11847                         token = read32 (ip + 1);
11848                         klass = mini_get_class (method, token, generic_context);
11849                         CHECK_TYPELOAD (klass);
11850                         if (ins_flag & MONO_INST_VOLATILE) {
11851                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11852                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11853                         }
11854                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
11855                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
11856                         ins->flags |= ins_flag;
11857                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
11858                                 generic_class_is_reference_type (cfg, klass) && !MONO_INS_IS_PCONST_NULL (sp [1])) {
11859                                 /* insert call to write barrier */
11860                                 emit_write_barrier (cfg, sp [0], sp [1]);
11861                         }
11862                         ins_flag = 0;
11863                         ip += 5;
11864                         inline_costs += 1;
11865                         break;
11866
11867                         /*
11868                          * Array opcodes
11869                          */
11870                 case CEE_NEWARR: {
11871                         MonoInst *len_ins;
11872                         const char *data_ptr;
11873                         int data_size = 0;
11874                         guint32 field_token;
11875
11876                         CHECK_STACK (1);
11877                         --sp;
11878
11879                         CHECK_OPSIZE (5);
11880                         token = read32 (ip + 1);
11881
11882                         klass = mini_get_class (method, token, generic_context);
11883                         CHECK_TYPELOAD (klass);
11884
11885                         context_used = mini_class_check_context_used (cfg, klass);
11886
11887                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
11888                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
11889                                 ins->sreg1 = sp [0]->dreg;
11890                                 ins->type = STACK_I4;
11891                                 ins->dreg = alloc_ireg (cfg);
11892                                 MONO_ADD_INS (cfg->cbb, ins);
11893                                 *sp = mono_decompose_opcode (cfg, ins);
11894                         }
11895
11896                         if (context_used) {
11897                                 MonoInst *args [3];
11898                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11899                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
11900
11901                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
11902
11903                                 /* vtable */
11904                                 args [0] = emit_get_rgctx_klass (cfg, context_used,
11905                                         array_class, MONO_RGCTX_INFO_VTABLE);
11906                                 /* array len */
11907                                 args [1] = sp [0];
11908
11909                                 if (managed_alloc)
11910                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
11911                                 else
11912                                         ins = mono_emit_jit_icall (cfg, ves_icall_array_new_specific, args);
11913                         } else {
11914                                 if (cfg->opt & MONO_OPT_SHARED) {
11915                                         /* Decompose now to avoid problems with references to the domainvar */
11916                                         MonoInst *iargs [3];
11917
11918                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11919                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11920                                         iargs [2] = sp [0];
11921
11922                                         ins = mono_emit_jit_icall (cfg, ves_icall_array_new, iargs);
11923                                 } else {
11924                                         /* Decompose later since it is needed by abcrem */
11925                                         MonoClass *array_type = mono_array_class_get (klass, 1);
11926                                         mono_class_vtable (cfg->domain, array_type);
11927                                         CHECK_TYPELOAD (array_type);
11928
11929                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
11930                                         ins->dreg = alloc_ireg_ref (cfg);
11931                                         ins->sreg1 = sp [0]->dreg;
11932                                         ins->inst_newa_class = klass;
11933                                         ins->type = STACK_OBJ;
11934                                         ins->klass = array_type;
11935                                         MONO_ADD_INS (cfg->cbb, ins);
11936                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11937                                         cfg->cbb->has_array_access = TRUE;
11938
11939                                         /* Needed so mono_emit_load_get_addr () gets called */
11940                                         mono_get_got_var (cfg);
11941                                 }
11942                         }
11943
11944                         len_ins = sp [0];
11945                         ip += 5;
11946                         *sp++ = ins;
11947                         inline_costs += 1;
11948
11949                         /* 
11950                          * we inline/optimize the initialization sequence if possible.
11951                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
11952                          * for small sizes open code the memcpy
11953                          * ensure the rva field is big enough
11954                          */
11955                         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))) {
11956                                 MonoMethod *memcpy_method = get_memcpy_method ();
11957                                 MonoInst *iargs [3];
11958                                 int add_reg = alloc_ireg_mp (cfg);
11959
11960                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, MONO_STRUCT_OFFSET (MonoArray, vector));
11961                                 if (cfg->compile_aot) {
11962                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
11963                                 } else {
11964                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
11965                                 }
11966                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
11967                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
11968                                 ip += 11;
11969                         }
11970
11971                         break;
11972                 }
11973                 case CEE_LDLEN:
11974                         CHECK_STACK (1);
11975                         --sp;
11976                         if (sp [0]->type != STACK_OBJ)
11977                                 UNVERIFIED;
11978
11979                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
11980                         ins->dreg = alloc_preg (cfg);
11981                         ins->sreg1 = sp [0]->dreg;
11982                         ins->type = STACK_I4;
11983                         /* This flag will be inherited by the decomposition */
11984                         ins->flags |= MONO_INST_FAULT;
11985                         MONO_ADD_INS (cfg->cbb, ins);
11986                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11987                         cfg->cbb->has_array_access = TRUE;
11988                         ip ++;
11989                         *sp++ = ins;
11990                         break;
11991                 case CEE_LDELEMA:
11992                         CHECK_STACK (2);
11993                         sp -= 2;
11994                         CHECK_OPSIZE (5);
11995                         if (sp [0]->type != STACK_OBJ)
11996                                 UNVERIFIED;
11997
11998                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11999
12000                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
12001                         CHECK_TYPELOAD (klass);
12002                         /* we need to make sure that this array is exactly the type it needs
12003                          * to be for correctness. the wrappers are lax with their usage
12004                          * so we need to ignore them here
12005                          */
12006                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
12007                                 MonoClass *array_class = mono_array_class_get (klass, 1);
12008                                 mini_emit_check_array_type (cfg, sp [0], array_class);
12009                                 CHECK_TYPELOAD (array_class);
12010                         }
12011
12012                         readonly = FALSE;
12013                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
12014                         *sp++ = ins;
12015                         ip += 5;
12016                         break;
12017                 case CEE_LDELEM:
12018                 case CEE_LDELEM_I1:
12019                 case CEE_LDELEM_U1:
12020                 case CEE_LDELEM_I2:
12021                 case CEE_LDELEM_U2:
12022                 case CEE_LDELEM_I4:
12023                 case CEE_LDELEM_U4:
12024                 case CEE_LDELEM_I8:
12025                 case CEE_LDELEM_I:
12026                 case CEE_LDELEM_R4:
12027                 case CEE_LDELEM_R8:
12028                 case CEE_LDELEM_REF: {
12029                         MonoInst *addr;
12030
12031                         CHECK_STACK (2);
12032                         sp -= 2;
12033
12034                         if (*ip == CEE_LDELEM) {
12035                                 CHECK_OPSIZE (5);
12036                                 token = read32 (ip + 1);
12037                                 klass = mini_get_class (method, token, generic_context);
12038                                 CHECK_TYPELOAD (klass);
12039                                 mono_class_init (klass);
12040                         }
12041                         else
12042                                 klass = array_access_to_klass (*ip);
12043
12044                         if (sp [0]->type != STACK_OBJ)
12045                                 UNVERIFIED;
12046
12047                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
12048
12049                         if (mini_is_gsharedvt_variable_klass (klass)) {
12050                                 // FIXME-VT: OP_ICONST optimization
12051                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
12052                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
12053                                 ins->opcode = OP_LOADV_MEMBASE;
12054                         } else if (sp [1]->opcode == OP_ICONST) {
12055                                 int array_reg = sp [0]->dreg;
12056                                 int index_reg = sp [1]->dreg;
12057                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
12058
12059                                 if (SIZEOF_REGISTER == 8 && COMPILE_LLVM (cfg))
12060                                         MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, index_reg);
12061
12062                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
12063                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
12064                         } else {
12065                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
12066                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
12067                         }
12068                         *sp++ = ins;
12069                         if (*ip == CEE_LDELEM)
12070                                 ip += 5;
12071                         else
12072                                 ++ip;
12073                         break;
12074                 }
12075                 case CEE_STELEM_I:
12076                 case CEE_STELEM_I1:
12077                 case CEE_STELEM_I2:
12078                 case CEE_STELEM_I4:
12079                 case CEE_STELEM_I8:
12080                 case CEE_STELEM_R4:
12081                 case CEE_STELEM_R8:
12082                 case CEE_STELEM_REF:
12083                 case CEE_STELEM: {
12084                         CHECK_STACK (3);
12085                         sp -= 3;
12086
12087                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
12088
12089                         if (*ip == CEE_STELEM) {
12090                                 CHECK_OPSIZE (5);
12091                                 token = read32 (ip + 1);
12092                                 klass = mini_get_class (method, token, generic_context);
12093                                 CHECK_TYPELOAD (klass);
12094                                 mono_class_init (klass);
12095                         }
12096                         else
12097                                 klass = array_access_to_klass (*ip);
12098
12099                         if (sp [0]->type != STACK_OBJ)
12100                                 UNVERIFIED;
12101
12102                         emit_array_store (cfg, klass, sp, TRUE);
12103
12104                         if (*ip == CEE_STELEM)
12105                                 ip += 5;
12106                         else
12107                                 ++ip;
12108                         inline_costs += 1;
12109                         break;
12110                 }
12111                 case CEE_CKFINITE: {
12112                         CHECK_STACK (1);
12113                         --sp;
12114
12115                         if (cfg->llvm_only) {
12116                                 MonoInst *iargs [1];
12117
12118                                 iargs [0] = sp [0];
12119                                 *sp++ = mono_emit_jit_icall (cfg, mono_ckfinite, iargs);
12120                         } else  {
12121                                 MONO_INST_NEW (cfg, ins, OP_CKFINITE);
12122                                 ins->sreg1 = sp [0]->dreg;
12123                                 ins->dreg = alloc_freg (cfg);
12124                                 ins->type = STACK_R8;
12125                                 MONO_ADD_INS (cfg->cbb, ins);
12126
12127                                 *sp++ = mono_decompose_opcode (cfg, ins);
12128                         }
12129
12130                         ++ip;
12131                         break;
12132                 }
12133                 case CEE_REFANYVAL: {
12134                         MonoInst *src_var, *src;
12135
12136                         int klass_reg = alloc_preg (cfg);
12137                         int dreg = alloc_preg (cfg);
12138
12139                         GSHAREDVT_FAILURE (*ip);
12140
12141                         CHECK_STACK (1);
12142                         MONO_INST_NEW (cfg, ins, *ip);
12143                         --sp;
12144                         CHECK_OPSIZE (5);
12145                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
12146                         CHECK_TYPELOAD (klass);
12147
12148                         context_used = mini_class_check_context_used (cfg, klass);
12149
12150                         // FIXME:
12151                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12152                         if (!src_var)
12153                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
12154                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
12155                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass));
12156
12157                         if (context_used) {
12158                                 MonoInst *klass_ins;
12159
12160                                 klass_ins = emit_get_rgctx_klass (cfg, context_used,
12161                                                 klass, MONO_RGCTX_INFO_KLASS);
12162
12163                                 // FIXME:
12164                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
12165                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
12166                         } else {
12167                                 mini_emit_class_check (cfg, klass_reg, klass);
12168                         }
12169                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value));
12170                         ins->type = STACK_MP;
12171                         ins->klass = klass;
12172                         *sp++ = ins;
12173                         ip += 5;
12174                         break;
12175                 }
12176                 case CEE_MKREFANY: {
12177                         MonoInst *loc, *addr;
12178
12179                         GSHAREDVT_FAILURE (*ip);
12180
12181                         CHECK_STACK (1);
12182                         MONO_INST_NEW (cfg, ins, *ip);
12183                         --sp;
12184                         CHECK_OPSIZE (5);
12185                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
12186                         CHECK_TYPELOAD (klass);
12187
12188                         context_used = mini_class_check_context_used (cfg, klass);
12189
12190                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
12191                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
12192
12193                         if (context_used) {
12194                                 MonoInst *const_ins;
12195                                 int type_reg = alloc_preg (cfg);
12196
12197                                 const_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
12198                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
12199                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
12200                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
12201                         } else {
12202                                 int const_reg = alloc_preg (cfg);
12203                                 int type_reg = alloc_preg (cfg);
12204
12205                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
12206                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
12207                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
12208                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
12209                         }
12210                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
12211
12212                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
12213                         ins->type = STACK_VTYPE;
12214                         ins->klass = mono_defaults.typed_reference_class;
12215                         *sp++ = ins;
12216                         ip += 5;
12217                         break;
12218                 }
12219                 case CEE_LDTOKEN: {
12220                         gpointer handle;
12221                         MonoClass *handle_class;
12222
12223                         CHECK_STACK_OVF (1);
12224
12225                         CHECK_OPSIZE (5);
12226                         n = read32 (ip + 1);
12227
12228                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
12229                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
12230                                 handle = mono_method_get_wrapper_data (method, n);
12231                                 handle_class = (MonoClass *)mono_method_get_wrapper_data (method, n + 1);
12232                                 if (handle_class == mono_defaults.typehandle_class)
12233                                         handle = &((MonoClass*)handle)->byval_arg;
12234                         }
12235                         else {
12236                                 handle = mono_ldtoken_checked (image, n, &handle_class, generic_context, &cfg->error);
12237                                 CHECK_CFG_ERROR;
12238                         }
12239                         if (!handle)
12240                                 LOAD_ERROR;
12241                         mono_class_init (handle_class);
12242                         if (cfg->gshared) {
12243                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
12244                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
12245                                         /* This case handles ldtoken
12246                                            of an open type, like for
12247                                            typeof(Gen<>). */
12248                                         context_used = 0;
12249                                 } else if (handle_class == mono_defaults.typehandle_class) {
12250                                         context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type ((MonoType *)handle));
12251                                 } else if (handle_class == mono_defaults.fieldhandle_class)
12252                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
12253                                 else if (handle_class == mono_defaults.methodhandle_class)
12254                                         context_used = mini_method_check_context_used (cfg, (MonoMethod *)handle);
12255                                 else
12256                                         g_assert_not_reached ();
12257                         }
12258
12259                         if ((cfg->opt & MONO_OPT_SHARED) &&
12260                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
12261                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
12262                                 MonoInst *addr, *vtvar, *iargs [3];
12263                                 int method_context_used;
12264
12265                                 method_context_used = mini_method_check_context_used (cfg, method);
12266
12267                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
12268
12269                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
12270                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
12271                                 if (method_context_used) {
12272                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
12273                                                 method, MONO_RGCTX_INFO_METHOD);
12274                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
12275                                 } else {
12276                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
12277                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
12278                                 }
12279                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12280
12281                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
12282
12283                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12284                         } else {
12285                                 if ((ip + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 5) && 
12286                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
12287                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
12288                                         (cmethod->klass == mono_defaults.systemtype_class) &&
12289                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
12290                                         MonoClass *tclass = mono_class_from_mono_type ((MonoType *)handle);
12291
12292                                         mono_class_init (tclass);
12293                                         if (context_used) {
12294                                                 ins = emit_get_rgctx_klass (cfg, context_used,
12295                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
12296                                         } else if (cfg->compile_aot) {
12297                                                 if (method->wrapper_type) {
12298                                                         mono_error_init (&error); //got to do it since there are multiple conditionals below
12299                                                         if (mono_class_get_checked (tclass->image, tclass->type_token, &error) == tclass && !generic_context) {
12300                                                                 /* Special case for static synchronized wrappers */
12301                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
12302                                                         } else {
12303                                                                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
12304                                                                 /* FIXME: n is not a normal token */
12305                                                                 DISABLE_AOT (cfg);
12306                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12307                                                         }
12308                                                 } else {
12309                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
12310                                                 }
12311                                         } else {
12312                                                 MonoReflectionType *rt = mono_type_get_object_checked (cfg->domain, (MonoType *)handle, &cfg->error);
12313                                                 CHECK_CFG_ERROR;
12314                                                 EMIT_NEW_PCONST (cfg, ins, rt);
12315                                         }
12316                                         ins->type = STACK_OBJ;
12317                                         ins->klass = cmethod->klass;
12318                                         ip += 5;
12319                                 } else {
12320                                         MonoInst *addr, *vtvar;
12321
12322                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
12323
12324                                         if (context_used) {
12325                                                 if (handle_class == mono_defaults.typehandle_class) {
12326                                                         ins = emit_get_rgctx_klass (cfg, context_used,
12327                                                                         mono_class_from_mono_type ((MonoType *)handle),
12328                                                                         MONO_RGCTX_INFO_TYPE);
12329                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
12330                                                         ins = emit_get_rgctx_method (cfg, context_used,
12331                                                                         (MonoMethod *)handle, MONO_RGCTX_INFO_METHOD);
12332                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
12333                                                         ins = emit_get_rgctx_field (cfg, context_used,
12334                                                                         (MonoClassField *)handle, MONO_RGCTX_INFO_CLASS_FIELD);
12335                                                 } else {
12336                                                         g_assert_not_reached ();
12337                                                 }
12338                                         } else if (cfg->compile_aot) {
12339                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
12340                                         } else {
12341                                                 EMIT_NEW_PCONST (cfg, ins, handle);
12342                                         }
12343                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12344                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
12345                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12346                                 }
12347                         }
12348
12349                         *sp++ = ins;
12350                         ip += 5;
12351                         break;
12352                 }
12353                 case CEE_THROW:
12354                         CHECK_STACK (1);
12355                         if (sp [-1]->type != STACK_OBJ)
12356                                 UNVERIFIED;
12357
12358                         MONO_INST_NEW (cfg, ins, OP_THROW);
12359                         --sp;
12360                         ins->sreg1 = sp [0]->dreg;
12361                         ip++;
12362                         cfg->cbb->out_of_line = TRUE;
12363                         MONO_ADD_INS (cfg->cbb, ins);
12364                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
12365                         MONO_ADD_INS (cfg->cbb, ins);
12366                         sp = stack_start;
12367                         
12368                         link_bblock (cfg, cfg->cbb, end_bblock);
12369                         start_new_bblock = 1;
12370                         /* This can complicate code generation for llvm since the return value might not be defined */
12371                         if (COMPILE_LLVM (cfg))
12372                                 INLINE_FAILURE ("throw");
12373                         break;
12374                 case CEE_ENDFINALLY:
12375                         if (!ip_in_finally_clause (cfg, ip - header->code))
12376                                 UNVERIFIED;
12377                         /* mono_save_seq_point_info () depends on this */
12378                         if (sp != stack_start)
12379                                 emit_seq_point (cfg, method, ip, FALSE, FALSE);
12380                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
12381                         MONO_ADD_INS (cfg->cbb, ins);
12382                         ip++;
12383                         start_new_bblock = 1;
12384
12385                         /*
12386                          * Control will leave the method so empty the stack, otherwise
12387                          * the next basic block will start with a nonempty stack.
12388                          */
12389                         while (sp != stack_start) {
12390                                 sp--;
12391                         }
12392                         break;
12393                 case CEE_LEAVE:
12394                 case CEE_LEAVE_S: {
12395                         GList *handlers;
12396
12397                         if (*ip == CEE_LEAVE) {
12398                                 CHECK_OPSIZE (5);
12399                                 target = ip + 5 + (gint32)read32(ip + 1);
12400                         } else {
12401                                 CHECK_OPSIZE (2);
12402                                 target = ip + 2 + (signed char)(ip [1]);
12403                         }
12404
12405                         /* empty the stack */
12406                         while (sp != stack_start) {
12407                                 sp--;
12408                         }
12409
12410                         /* 
12411                          * If this leave statement is in a catch block, check for a
12412                          * pending exception, and rethrow it if necessary.
12413                          * We avoid doing this in runtime invoke wrappers, since those are called
12414                          * by native code which excepts the wrapper to catch all exceptions.
12415                          */
12416                         for (i = 0; i < header->num_clauses; ++i) {
12417                                 MonoExceptionClause *clause = &header->clauses [i];
12418
12419                                 /* 
12420                                  * Use <= in the final comparison to handle clauses with multiple
12421                                  * leave statements, like in bug #78024.
12422                                  * The ordering of the exception clauses guarantees that we find the
12423                                  * innermost clause.
12424                                  */
12425                                 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) {
12426                                         MonoInst *exc_ins;
12427                                         MonoBasicBlock *dont_throw;
12428
12429                                         /*
12430                                           MonoInst *load;
12431
12432                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
12433                                         */
12434
12435                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
12436
12437                                         NEW_BBLOCK (cfg, dont_throw);
12438
12439                                         /*
12440                                          * Currently, we always rethrow the abort exception, despite the 
12441                                          * fact that this is not correct. See thread6.cs for an example. 
12442                                          * But propagating the abort exception is more important than 
12443                                          * getting the sematics right.
12444                                          */
12445                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
12446                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
12447                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
12448
12449                                         MONO_START_BB (cfg, dont_throw);
12450                                 }
12451                         }
12452
12453 #ifdef ENABLE_LLVM
12454                         cfg->cbb->try_end = (intptr_t)(ip - header->code);
12455 #endif
12456
12457                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
12458                                 GList *tmp;
12459                                 MonoExceptionClause *clause;
12460
12461                                 for (tmp = handlers; tmp; tmp = tmp->next) {
12462                                         clause = (MonoExceptionClause *)tmp->data;
12463                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
12464                                         g_assert (tblock);
12465                                         link_bblock (cfg, cfg->cbb, tblock);
12466                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
12467                                         ins->inst_target_bb = tblock;
12468                                         ins->inst_eh_block = clause;
12469                                         MONO_ADD_INS (cfg->cbb, ins);
12470                                         cfg->cbb->has_call_handler = 1;
12471                                         if (COMPILE_LLVM (cfg)) {
12472                                                 MonoBasicBlock *target_bb;
12473
12474                                                 /* 
12475                                                  * Link the finally bblock with the target, since it will
12476                                                  * conceptually branch there.
12477                                                  */
12478                                                 GET_BBLOCK (cfg, tblock, cfg->cil_start + clause->handler_offset + clause->handler_len - 1);
12479                                                 GET_BBLOCK (cfg, target_bb, target);
12480                                                 link_bblock (cfg, tblock, target_bb);
12481                                         }
12482                                 }
12483                                 g_list_free (handlers);
12484                         } 
12485
12486                         MONO_INST_NEW (cfg, ins, OP_BR);
12487                         MONO_ADD_INS (cfg->cbb, ins);
12488                         GET_BBLOCK (cfg, tblock, target);
12489                         link_bblock (cfg, cfg->cbb, tblock);
12490                         ins->inst_target_bb = tblock;
12491
12492                         start_new_bblock = 1;
12493
12494                         if (*ip == CEE_LEAVE)
12495                                 ip += 5;
12496                         else
12497                                 ip += 2;
12498
12499                         break;
12500                 }
12501
12502                         /*
12503                          * Mono specific opcodes
12504                          */
12505                 case MONO_CUSTOM_PREFIX: {
12506
12507                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
12508
12509                         CHECK_OPSIZE (2);
12510                         switch (ip [1]) {
12511                         case CEE_MONO_ICALL: {
12512                                 gpointer func;
12513                                 MonoJitICallInfo *info;
12514
12515                                 token = read32 (ip + 2);
12516                                 func = mono_method_get_wrapper_data (method, token);
12517                                 info = mono_find_jit_icall_by_addr (func);
12518                                 if (!info)
12519                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
12520                                 g_assert (info);
12521
12522                                 CHECK_STACK (info->sig->param_count);
12523                                 sp -= info->sig->param_count;
12524
12525                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
12526                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
12527                                         *sp++ = ins;
12528
12529                                 ip += 6;
12530                                 inline_costs += 10 * num_calls++;
12531
12532                                 break;
12533                         }
12534                         case CEE_MONO_LDPTR_CARD_TABLE:
12535                         case CEE_MONO_LDPTR_NURSERY_START:
12536                         case CEE_MONO_LDPTR_NURSERY_BITS:
12537                         case CEE_MONO_LDPTR_INT_REQ_FLAG: {
12538                                 CHECK_STACK_OVF (1);
12539
12540                                 switch (ip [1]) {
12541                                         case CEE_MONO_LDPTR_CARD_TABLE:
12542                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
12543                                                 break;
12544                                         case CEE_MONO_LDPTR_NURSERY_START:
12545                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_START, NULL);
12546                                                 break;
12547                                         case CEE_MONO_LDPTR_NURSERY_BITS:
12548                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_BITS, NULL);
12549                                                 break;
12550                                         case CEE_MONO_LDPTR_INT_REQ_FLAG:
12551                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
12552                                                 break;
12553                                 }
12554
12555                                 *sp++ = ins;
12556                                 ip += 2;
12557                                 inline_costs += 10 * num_calls++;
12558                                 break;
12559                         }
12560                         case CEE_MONO_LDPTR: {
12561                                 gpointer ptr;
12562
12563                                 CHECK_STACK_OVF (1);
12564                                 CHECK_OPSIZE (6);
12565                                 token = read32 (ip + 2);
12566
12567                                 ptr = mono_method_get_wrapper_data (method, token);
12568                                 EMIT_NEW_PCONST (cfg, ins, ptr);
12569                                 *sp++ = ins;
12570                                 ip += 6;
12571                                 inline_costs += 10 * num_calls++;
12572                                 /* Can't embed random pointers into AOT code */
12573                                 DISABLE_AOT (cfg);
12574                                 break;
12575                         }
12576                         case CEE_MONO_JIT_ICALL_ADDR: {
12577                                 MonoJitICallInfo *callinfo;
12578                                 gpointer ptr;
12579
12580                                 CHECK_STACK_OVF (1);
12581                                 CHECK_OPSIZE (6);
12582                                 token = read32 (ip + 2);
12583
12584                                 ptr = mono_method_get_wrapper_data (method, token);
12585                                 callinfo = mono_find_jit_icall_by_addr (ptr);
12586                                 g_assert (callinfo);
12587                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
12588                                 *sp++ = ins;
12589                                 ip += 6;
12590                                 inline_costs += 10 * num_calls++;
12591                                 break;
12592                         }
12593                         case CEE_MONO_ICALL_ADDR: {
12594                                 MonoMethod *cmethod;
12595                                 gpointer ptr;
12596
12597                                 CHECK_STACK_OVF (1);
12598                                 CHECK_OPSIZE (6);
12599                                 token = read32 (ip + 2);
12600
12601                                 cmethod = (MonoMethod *)mono_method_get_wrapper_data (method, token);
12602
12603                                 if (cfg->compile_aot) {
12604                                         if (cfg->direct_pinvoke && ip + 6 < end && (ip [6] == CEE_POP)) {
12605                                                 /*
12606                                                  * This is generated by emit_native_wrapper () to resolve the pinvoke address
12607                                                  * before the call, its not needed when using direct pinvoke.
12608                                                  * This is not an optimization, but its used to avoid looking up pinvokes
12609                                                  * on platforms which don't support dlopen ().
12610                                                  */
12611                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12612                                         } else {
12613                                                 EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
12614                                         }
12615                                 } else {
12616                                         ptr = mono_lookup_internal_call (cmethod);
12617                                         g_assert (ptr);
12618                                         EMIT_NEW_PCONST (cfg, ins, ptr);
12619                                 }
12620                                 *sp++ = ins;
12621                                 ip += 6;
12622                                 break;
12623                         }
12624                         case CEE_MONO_VTADDR: {
12625                                 MonoInst *src_var, *src;
12626
12627                                 CHECK_STACK (1);
12628                                 --sp;
12629
12630                                 // FIXME:
12631                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12632                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
12633                                 *sp++ = src;
12634                                 ip += 2;
12635                                 break;
12636                         }
12637                         case CEE_MONO_NEWOBJ: {
12638                                 MonoInst *iargs [2];
12639
12640                                 CHECK_STACK_OVF (1);
12641                                 CHECK_OPSIZE (6);
12642                                 token = read32 (ip + 2);
12643                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12644                                 mono_class_init (klass);
12645                                 NEW_DOMAINCONST (cfg, iargs [0]);
12646                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
12647                                 NEW_CLASSCONST (cfg, iargs [1], klass);
12648                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
12649                                 *sp++ = mono_emit_jit_icall (cfg, ves_icall_object_new, iargs);
12650                                 ip += 6;
12651                                 inline_costs += 10 * num_calls++;
12652                                 break;
12653                         }
12654                         case CEE_MONO_OBJADDR:
12655                                 CHECK_STACK (1);
12656                                 --sp;
12657                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
12658                                 ins->dreg = alloc_ireg_mp (cfg);
12659                                 ins->sreg1 = sp [0]->dreg;
12660                                 ins->type = STACK_MP;
12661                                 MONO_ADD_INS (cfg->cbb, ins);
12662                                 *sp++ = ins;
12663                                 ip += 2;
12664                                 break;
12665                         case CEE_MONO_LDNATIVEOBJ:
12666                                 /*
12667                                  * Similar to LDOBJ, but instead load the unmanaged 
12668                                  * representation of the vtype to the stack.
12669                                  */
12670                                 CHECK_STACK (1);
12671                                 CHECK_OPSIZE (6);
12672                                 --sp;
12673                                 token = read32 (ip + 2);
12674                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12675                                 g_assert (klass->valuetype);
12676                                 mono_class_init (klass);
12677
12678                                 {
12679                                         MonoInst *src, *dest, *temp;
12680
12681                                         src = sp [0];
12682                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
12683                                         temp->backend.is_pinvoke = 1;
12684                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
12685                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
12686
12687                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
12688                                         dest->type = STACK_VTYPE;
12689                                         dest->klass = klass;
12690
12691                                         *sp ++ = dest;
12692                                         ip += 6;
12693                                 }
12694                                 break;
12695                         case CEE_MONO_RETOBJ: {
12696                                 /*
12697                                  * Same as RET, but return the native representation of a vtype
12698                                  * to the caller.
12699                                  */
12700                                 g_assert (cfg->ret);
12701                                 g_assert (mono_method_signature (method)->pinvoke); 
12702                                 CHECK_STACK (1);
12703                                 --sp;
12704                                 
12705                                 CHECK_OPSIZE (6);
12706                                 token = read32 (ip + 2);    
12707                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12708
12709                                 if (!cfg->vret_addr) {
12710                                         g_assert (cfg->ret_var_is_local);
12711
12712                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
12713                                 } else {
12714                                         EMIT_NEW_RETLOADA (cfg, ins);
12715                                 }
12716                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
12717                                 
12718                                 if (sp != stack_start)
12719                                         UNVERIFIED;
12720                                 
12721                                 MONO_INST_NEW (cfg, ins, OP_BR);
12722                                 ins->inst_target_bb = end_bblock;
12723                                 MONO_ADD_INS (cfg->cbb, ins);
12724                                 link_bblock (cfg, cfg->cbb, end_bblock);
12725                                 start_new_bblock = 1;
12726                                 ip += 6;
12727                                 break;
12728                         }
12729                         case CEE_MONO_CISINST:
12730                         case CEE_MONO_CCASTCLASS: {
12731                                 int token;
12732                                 CHECK_STACK (1);
12733                                 --sp;
12734                                 CHECK_OPSIZE (6);
12735                                 token = read32 (ip + 2);
12736                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12737                                 if (ip [1] == CEE_MONO_CISINST)
12738                                         ins = handle_cisinst (cfg, klass, sp [0]);
12739                                 else
12740                                         ins = handle_ccastclass (cfg, klass, sp [0]);
12741                                 *sp++ = ins;
12742                                 ip += 6;
12743                                 break;
12744                         }
12745                         case CEE_MONO_SAVE_LMF:
12746                         case CEE_MONO_RESTORE_LMF:
12747                                 ip += 2;
12748                                 break;
12749                         case CEE_MONO_CLASSCONST:
12750                                 CHECK_STACK_OVF (1);
12751                                 CHECK_OPSIZE (6);
12752                                 token = read32 (ip + 2);
12753                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
12754                                 *sp++ = ins;
12755                                 ip += 6;
12756                                 inline_costs += 10 * num_calls++;
12757                                 break;
12758                         case CEE_MONO_NOT_TAKEN:
12759                                 cfg->cbb->out_of_line = TRUE;
12760                                 ip += 2;
12761                                 break;
12762                         case CEE_MONO_TLS: {
12763                                 MonoTlsKey key;
12764
12765                                 CHECK_STACK_OVF (1);
12766                                 CHECK_OPSIZE (6);
12767                                 key = (MonoTlsKey)read32 (ip + 2);
12768                                 g_assert (key < TLS_KEY_NUM);
12769
12770                                 ins = mono_create_tls_get (cfg, key);
12771                                 if (!ins) {
12772                                         if (cfg->compile_aot) {
12773                                                 DISABLE_AOT (cfg);
12774                                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
12775                                                 ins->dreg = alloc_preg (cfg);
12776                                                 ins->type = STACK_PTR;
12777                                         } else {
12778                                                 g_assert_not_reached ();
12779                                         }
12780                                 }
12781                                 ins->type = STACK_PTR;
12782                                 MONO_ADD_INS (cfg->cbb, ins);
12783                                 *sp++ = ins;
12784                                 ip += 6;
12785                                 break;
12786                         }
12787                         case CEE_MONO_DYN_CALL: {
12788                                 MonoCallInst *call;
12789
12790                                 /* It would be easier to call a trampoline, but that would put an
12791                                  * extra frame on the stack, confusing exception handling. So
12792                                  * implement it inline using an opcode for now.
12793                                  */
12794
12795                                 if (!cfg->dyn_call_var) {
12796                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12797                                         /* prevent it from being register allocated */
12798                                         cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
12799                                 }
12800
12801                                 /* Has to use a call inst since it local regalloc expects it */
12802                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
12803                                 ins = (MonoInst*)call;
12804                                 sp -= 2;
12805                                 ins->sreg1 = sp [0]->dreg;
12806                                 ins->sreg2 = sp [1]->dreg;
12807                                 MONO_ADD_INS (cfg->cbb, ins);
12808
12809                                 cfg->param_area = MAX (cfg->param_area, cfg->backend->dyn_call_param_area);
12810
12811                                 ip += 2;
12812                                 inline_costs += 10 * num_calls++;
12813
12814                                 break;
12815                         }
12816                         case CEE_MONO_MEMORY_BARRIER: {
12817                                 CHECK_OPSIZE (6);
12818                                 emit_memory_barrier (cfg, (int)read32 (ip + 2));
12819                                 ip += 6;
12820                                 break;
12821                         }
12822                         case CEE_MONO_ATOMIC_STORE_I4: {
12823                                 g_assert (mono_arch_opcode_supported (OP_ATOMIC_STORE_I4));
12824
12825                                 CHECK_OPSIZE (6);
12826                                 CHECK_STACK (2);
12827                                 sp -= 2;
12828
12829                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_STORE_I4);
12830                                 ins->dreg = sp [0]->dreg;
12831                                 ins->sreg1 = sp [1]->dreg;
12832                                 ins->backend.memory_barrier_kind = (int) read32 (ip + 2);
12833                                 MONO_ADD_INS (cfg->cbb, ins);
12834
12835                                 ip += 6;
12836                                 break;
12837                         }
12838                         case CEE_MONO_JIT_ATTACH: {
12839                                 MonoInst *args [16], *domain_ins;
12840                                 MonoInst *ad_ins, *jit_tls_ins;
12841                                 MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
12842
12843                                 g_assert (!mono_threads_is_coop_enabled ());
12844
12845                                 cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12846
12847                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12848                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12849
12850                                 ad_ins = mono_get_domain_intrinsic (cfg);
12851                                 jit_tls_ins = mono_get_jit_tls_intrinsic (cfg);
12852
12853                                 if (cfg->backend->have_tls_get && ad_ins && jit_tls_ins) {
12854                                         NEW_BBLOCK (cfg, next_bb);
12855                                         NEW_BBLOCK (cfg, call_bb);
12856
12857                                         if (cfg->compile_aot) {
12858                                                 /* AOT code is only used in the root domain */
12859                                                 EMIT_NEW_PCONST (cfg, domain_ins, NULL);
12860                                         } else {
12861                                                 EMIT_NEW_PCONST (cfg, domain_ins, cfg->domain);
12862                                         }
12863                                         MONO_ADD_INS (cfg->cbb, ad_ins);
12864                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg);
12865                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb);
12866
12867                                         MONO_ADD_INS (cfg->cbb, jit_tls_ins);
12868                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0);
12869                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb);
12870
12871                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb);
12872                                         MONO_START_BB (cfg, call_bb);
12873                                 }
12874
12875                                 /* AOT code is only used in the root domain */
12876                                 EMIT_NEW_PCONST (cfg, args [0], cfg->compile_aot ? NULL : cfg->domain);
12877                                 if (cfg->compile_aot) {
12878                                         MonoInst *addr;
12879
12880                                         /*
12881                                          * This is called on unattached threads, so it cannot go through the trampoline
12882                                          * infrastructure. Use an indirect call through a got slot initialized at load time
12883                                          * instead.
12884                                          */
12885                                         EMIT_NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_JIT_THREAD_ATTACH, NULL);
12886                                         ins = mono_emit_calli (cfg, helper_sig_jit_thread_attach, args, addr, NULL, NULL);
12887                                 } else {
12888                                         ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
12889                                 }
12890                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12891
12892                                 if (next_bb)
12893                                         MONO_START_BB (cfg, next_bb);
12894
12895                                 ip += 2;
12896                                 break;
12897                         }
12898                         case CEE_MONO_JIT_DETACH: {
12899                                 MonoInst *args [16];
12900
12901                                 /* Restore the original domain */
12902                                 dreg = alloc_ireg (cfg);
12903                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->orig_domain_var->dreg);
12904                                 mono_emit_jit_icall (cfg, mono_jit_set_domain, args);
12905                                 ip += 2;
12906                                 break;
12907                         }
12908                         case CEE_MONO_CALLI_EXTRA_ARG: {
12909                                 MonoInst *addr;
12910                                 MonoMethodSignature *fsig;
12911                                 MonoInst *arg;
12912
12913                                 /*
12914                                  * This is the same as CEE_CALLI, but passes an additional argument
12915                                  * to the called method in llvmonly mode.
12916                                  * This is only used by delegate invoke wrappers to call the
12917                                  * actual delegate method.
12918                                  */
12919                                 g_assert (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE);
12920
12921                                 CHECK_OPSIZE (6);
12922                                 token = read32 (ip + 2);
12923
12924                                 ins = NULL;
12925
12926                                 cmethod = NULL;
12927                                 CHECK_STACK (1);
12928                                 --sp;
12929                                 addr = *sp;
12930                                 fsig = mini_get_signature (method, token, generic_context, &cfg->error);
12931                                 CHECK_CFG_ERROR;
12932
12933                                 if (cfg->llvm_only)
12934                                         cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
12935
12936                                 n = fsig->param_count + fsig->hasthis + 1;
12937
12938                                 CHECK_STACK (n);
12939
12940                                 sp -= n;
12941                                 arg = sp [n - 1];
12942
12943                                 if (cfg->llvm_only) {
12944                                         /*
12945                                          * The lowest bit of 'arg' determines whenever the callee uses the gsharedvt
12946                                          * cconv. This is set by mono_init_delegate ().
12947                                          */
12948                                         if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig)) {
12949                                                 MonoInst *callee = addr;
12950                                                 MonoInst *call, *localloc_ins;
12951                                                 MonoBasicBlock *is_gsharedvt_bb, *end_bb;
12952                                                 int low_bit_reg = alloc_preg (cfg);
12953
12954                                                 NEW_BBLOCK (cfg, is_gsharedvt_bb);
12955                                                 NEW_BBLOCK (cfg, end_bb);
12956
12957                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
12958                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
12959                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
12960
12961                                                 /* Normal case: callee uses a normal cconv, have to add an out wrapper */
12962                                                 addr = emit_get_rgctx_sig (cfg, context_used,
12963                                                                                                    fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
12964                                                 /*
12965                                                  * ADDR points to a gsharedvt-out wrapper, have to pass <callee, arg> as an extra arg.
12966                                                  */
12967                                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
12968                                                 ins->dreg = alloc_preg (cfg);
12969                                                 ins->inst_imm = 2 * SIZEOF_VOID_P;
12970                                                 MONO_ADD_INS (cfg->cbb, ins);
12971                                                 localloc_ins = ins;
12972                                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12973                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
12974                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
12975
12976                                                 call = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
12977                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12978
12979                                                 /* Gsharedvt case: callee uses a gsharedvt cconv, no conversion is needed */
12980                                                 MONO_START_BB (cfg, is_gsharedvt_bb);
12981                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
12982                                                 ins = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
12983                                                 ins->dreg = call->dreg;
12984
12985                                                 MONO_START_BB (cfg, end_bb);
12986                                         } else {
12987                                                 /* Caller uses a normal calling conv */
12988
12989                                                 MonoInst *callee = addr;
12990                                                 MonoInst *call, *localloc_ins;
12991                                                 MonoBasicBlock *is_gsharedvt_bb, *end_bb;
12992                                                 int low_bit_reg = alloc_preg (cfg);
12993
12994                                                 NEW_BBLOCK (cfg, is_gsharedvt_bb);
12995                                                 NEW_BBLOCK (cfg, end_bb);
12996
12997                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
12998                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
12999                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
13000
13001                                                 /* Normal case: callee uses a normal cconv, no conversion is needed */
13002                                                 call = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
13003                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
13004                                                 /* Gsharedvt case: callee uses a gsharedvt cconv, have to add an in wrapper */
13005                                                 MONO_START_BB (cfg, is_gsharedvt_bb);
13006                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
13007                                                 NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER, fsig);
13008                                                 MONO_ADD_INS (cfg->cbb, addr);
13009                                                 /*
13010                                                  * ADDR points to a gsharedvt-in wrapper, have to pass <callee, arg> as an extra arg.
13011                                                  */
13012                                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
13013                                                 ins->dreg = alloc_preg (cfg);
13014                                                 ins->inst_imm = 2 * SIZEOF_VOID_P;
13015                                                 MONO_ADD_INS (cfg->cbb, ins);
13016                                                 localloc_ins = ins;
13017                                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
13018                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
13019                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
13020
13021                                                 ins = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
13022                                                 ins->dreg = call->dreg;
13023                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
13024
13025                                                 MONO_START_BB (cfg, end_bb);
13026                                         }
13027                                 } else {
13028                                         /* Same as CEE_CALLI */
13029                                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
13030                                                 /*
13031                                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
13032                                                  */
13033                                                 MonoInst *callee = addr;
13034
13035                                                 addr = emit_get_rgctx_sig (cfg, context_used,
13036                                                                                                    fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
13037                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
13038                                         } else {
13039                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
13040                                         }
13041                                 }
13042
13043                                 if (!MONO_TYPE_IS_VOID (fsig->ret))
13044                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
13045
13046                                 CHECK_CFG_EXCEPTION;
13047
13048                                 ip += 6;
13049                                 ins_flag = 0;
13050                                 constrained_class = NULL;
13051                                 break;
13052                         }
13053                         case CEE_MONO_LDDOMAIN:
13054                                 CHECK_STACK_OVF (1);
13055                                 EMIT_NEW_PCONST (cfg, ins, cfg->compile_aot ? NULL : cfg->domain);
13056                                 ip += 2;
13057                                 *sp++ = ins;
13058                                 break;
13059                         case CEE_MONO_GET_LAST_ERROR:
13060                                 CHECK_OPSIZE (2);
13061                                 CHECK_STACK_OVF (1);
13062
13063                                 MONO_INST_NEW (cfg, ins, OP_GET_LAST_ERROR);
13064                                 ins->dreg = alloc_dreg (cfg, STACK_I4);
13065                                 ins->type = STACK_I4;
13066                                 MONO_ADD_INS (cfg->cbb, ins);
13067
13068                                 ip += 2;
13069                                 *sp++ = ins;
13070                                 break;
13071                         default:
13072                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
13073                                 break;
13074                         }
13075                         break;
13076                 }
13077
13078                 case CEE_PREFIX1: {
13079                         CHECK_OPSIZE (2);
13080                         switch (ip [1]) {
13081                         case CEE_ARGLIST: {
13082                                 /* somewhat similar to LDTOKEN */
13083                                 MonoInst *addr, *vtvar;
13084                                 CHECK_STACK_OVF (1);
13085                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
13086
13087                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
13088                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
13089
13090                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
13091                                 ins->type = STACK_VTYPE;
13092                                 ins->klass = mono_defaults.argumenthandle_class;
13093                                 *sp++ = ins;
13094                                 ip += 2;
13095                                 break;
13096                         }
13097                         case CEE_CEQ:
13098                         case CEE_CGT:
13099                         case CEE_CGT_UN:
13100                         case CEE_CLT:
13101                         case CEE_CLT_UN: {
13102                                 MonoInst *cmp, *arg1, *arg2;
13103
13104                                 CHECK_STACK (2);
13105                                 sp -= 2;
13106                                 arg1 = sp [0];
13107                                 arg2 = sp [1];
13108
13109                                 /*
13110                                  * The following transforms:
13111                                  *    CEE_CEQ    into OP_CEQ
13112                                  *    CEE_CGT    into OP_CGT
13113                                  *    CEE_CGT_UN into OP_CGT_UN
13114                                  *    CEE_CLT    into OP_CLT
13115                                  *    CEE_CLT_UN into OP_CLT_UN
13116                                  */
13117                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
13118
13119                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
13120                                 cmp->sreg1 = arg1->dreg;
13121                                 cmp->sreg2 = arg2->dreg;
13122                                 type_from_op (cfg, cmp, arg1, arg2);
13123                                 CHECK_TYPE (cmp);
13124                                 add_widen_op (cfg, cmp, &arg1, &arg2);
13125                                 if ((arg1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((arg1->type == STACK_PTR) || (arg1->type == STACK_OBJ) || (arg1->type == STACK_MP))))
13126                                         cmp->opcode = OP_LCOMPARE;
13127                                 else if (arg1->type == STACK_R4)
13128                                         cmp->opcode = OP_RCOMPARE;
13129                                 else if (arg1->type == STACK_R8)
13130                                         cmp->opcode = OP_FCOMPARE;
13131                                 else
13132                                         cmp->opcode = OP_ICOMPARE;
13133                                 MONO_ADD_INS (cfg->cbb, cmp);
13134                                 ins->type = STACK_I4;
13135                                 ins->dreg = alloc_dreg (cfg, (MonoStackType)ins->type);
13136                                 type_from_op (cfg, ins, arg1, arg2);
13137
13138                                 if (cmp->opcode == OP_FCOMPARE || cmp->opcode == OP_RCOMPARE) {
13139                                         /*
13140                                          * The backends expect the fceq opcodes to do the
13141                                          * comparison too.
13142                                          */
13143                                         ins->sreg1 = cmp->sreg1;
13144                                         ins->sreg2 = cmp->sreg2;
13145                                         NULLIFY_INS (cmp);
13146                                 }
13147                                 MONO_ADD_INS (cfg->cbb, ins);
13148                                 *sp++ = ins;
13149                                 ip += 2;
13150                                 break;
13151                         }
13152                         case CEE_LDFTN: {
13153                                 MonoInst *argconst;
13154                                 MonoMethod *cil_method;
13155
13156                                 CHECK_STACK_OVF (1);
13157                                 CHECK_OPSIZE (6);
13158                                 n = read32 (ip + 2);
13159                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
13160                                 CHECK_CFG_ERROR;
13161
13162                                 mono_class_init (cmethod->klass);
13163
13164                                 mono_save_token_info (cfg, image, n, cmethod);
13165
13166                                 context_used = mini_method_check_context_used (cfg, cmethod);
13167
13168                                 cil_method = cmethod;
13169                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
13170                                         emit_method_access_failure (cfg, method, cil_method);
13171
13172                                 if (mono_security_core_clr_enabled ())
13173                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
13174
13175                                 /* 
13176                                  * Optimize the common case of ldftn+delegate creation
13177                                  */
13178                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
13179                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
13180                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
13181                                                 MonoInst *target_ins, *handle_ins;
13182                                                 MonoMethod *invoke;
13183                                                 int invoke_context_used;
13184
13185                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
13186                                                 if (!invoke || !mono_method_signature (invoke))
13187                                                         LOAD_ERROR;
13188
13189                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
13190
13191                                                 target_ins = sp [-1];
13192
13193                                                 if (mono_security_core_clr_enabled ())
13194                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
13195
13196                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
13197                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
13198                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
13199                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
13200                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
13201                                                         }
13202                                                 }
13203
13204                                                 /* FIXME: SGEN support */
13205                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
13206                                                         ip += 6;
13207                                                         if (cfg->verbose_level > 3)
13208                                                                 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));
13209                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, FALSE))) {
13210                                                                 sp --;
13211                                                                 *sp = handle_ins;
13212                                                                 CHECK_CFG_EXCEPTION;
13213                                                                 ip += 5;
13214                                                                 sp ++;
13215                                                                 break;
13216                                                         }
13217                                                         ip -= 6;
13218                                                 }
13219                                         }
13220                                 }
13221
13222                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
13223                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
13224                                 *sp++ = ins;
13225                                 
13226                                 ip += 6;
13227                                 inline_costs += 10 * num_calls++;
13228                                 break;
13229                         }
13230                         case CEE_LDVIRTFTN: {
13231                                 MonoInst *args [2];
13232
13233                                 CHECK_STACK (1);
13234                                 CHECK_OPSIZE (6);
13235                                 n = read32 (ip + 2);
13236                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
13237                                 CHECK_CFG_ERROR;
13238
13239                                 mono_class_init (cmethod->klass);
13240  
13241                                 context_used = mini_method_check_context_used (cfg, cmethod);
13242
13243                                 if (mono_security_core_clr_enabled ())
13244                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
13245
13246                                 /*
13247                                  * Optimize the common case of ldvirtftn+delegate creation
13248                                  */
13249                                 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)) {
13250                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
13251                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
13252                                                 MonoInst *target_ins, *handle_ins;
13253                                                 MonoMethod *invoke;
13254                                                 int invoke_context_used;
13255                                                 gboolean is_virtual = cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL;
13256
13257                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
13258                                                 if (!invoke || !mono_method_signature (invoke))
13259                                                         LOAD_ERROR;
13260
13261                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
13262
13263                                                 target_ins = sp [-1];
13264
13265                                                 if (mono_security_core_clr_enabled ())
13266                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
13267
13268                                                 /* FIXME: SGEN support */
13269                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
13270                                                         ip += 6;
13271                                                         if (cfg->verbose_level > 3)
13272                                                                 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));
13273                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, is_virtual))) {
13274                                                                 sp -= 2;
13275                                                                 *sp = handle_ins;
13276                                                                 CHECK_CFG_EXCEPTION;
13277                                                                 ip += 5;
13278                                                                 sp ++;
13279                                                                 break;
13280                                                         }
13281                                                         ip -= 6;
13282                                                 }
13283                                         }
13284                                 }
13285
13286                                 --sp;
13287                                 args [0] = *sp;
13288
13289                                 args [1] = emit_get_rgctx_method (cfg, context_used,
13290                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
13291
13292                                 if (context_used)
13293                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
13294                                 else
13295                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
13296
13297                                 ip += 6;
13298                                 inline_costs += 10 * num_calls++;
13299                                 break;
13300                         }
13301                         case CEE_LDARG:
13302                                 CHECK_STACK_OVF (1);
13303                                 CHECK_OPSIZE (4);
13304                                 n = read16 (ip + 2);
13305                                 CHECK_ARG (n);
13306                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
13307                                 *sp++ = ins;
13308                                 ip += 4;
13309                                 break;
13310                         case CEE_LDARGA:
13311                                 CHECK_STACK_OVF (1);
13312                                 CHECK_OPSIZE (4);
13313                                 n = read16 (ip + 2);
13314                                 CHECK_ARG (n);
13315                                 NEW_ARGLOADA (cfg, ins, n);
13316                                 MONO_ADD_INS (cfg->cbb, ins);
13317                                 *sp++ = ins;
13318                                 ip += 4;
13319                                 break;
13320                         case CEE_STARG:
13321                                 CHECK_STACK (1);
13322                                 --sp;
13323                                 CHECK_OPSIZE (4);
13324                                 n = read16 (ip + 2);
13325                                 CHECK_ARG (n);
13326                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
13327                                         UNVERIFIED;
13328                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
13329                                 ip += 4;
13330                                 break;
13331                         case CEE_LDLOC:
13332                                 CHECK_STACK_OVF (1);
13333                                 CHECK_OPSIZE (4);
13334                                 n = read16 (ip + 2);
13335                                 CHECK_LOCAL (n);
13336                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
13337                                 *sp++ = ins;
13338                                 ip += 4;
13339                                 break;
13340                         case CEE_LDLOCA: {
13341                                 unsigned char *tmp_ip;
13342                                 CHECK_STACK_OVF (1);
13343                                 CHECK_OPSIZE (4);
13344                                 n = read16 (ip + 2);
13345                                 CHECK_LOCAL (n);
13346
13347                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
13348                                         ip = tmp_ip;
13349                                         inline_costs += 1;
13350                                         break;
13351                                 }                       
13352                                 
13353                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
13354                                 *sp++ = ins;
13355                                 ip += 4;
13356                                 break;
13357                         }
13358                         case CEE_STLOC:
13359                                 CHECK_STACK (1);
13360                                 --sp;
13361                                 CHECK_OPSIZE (4);
13362                                 n = read16 (ip + 2);
13363                                 CHECK_LOCAL (n);
13364                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
13365                                         UNVERIFIED;
13366                                 emit_stloc_ir (cfg, sp, header, n);
13367                                 ip += 4;
13368                                 inline_costs += 1;
13369                                 break;
13370                         case CEE_LOCALLOC: {
13371                                 CHECK_STACK (1);
13372                                 MonoBasicBlock *non_zero_bb, *end_bb;
13373                                 int alloc_ptr = alloc_preg (cfg);
13374                                 --sp;
13375                                 if (sp != stack_start) 
13376                                         UNVERIFIED;
13377                                 if (cfg->method != method) 
13378                                         /* 
13379                                          * Inlining this into a loop in a parent could lead to 
13380                                          * stack overflows which is different behavior than the
13381                                          * non-inlined case, thus disable inlining in this case.
13382                                          */
13383                                         INLINE_FAILURE("localloc");
13384
13385                                 NEW_BBLOCK (cfg, non_zero_bb);
13386                                 NEW_BBLOCK (cfg, end_bb);
13387
13388                                 /* if size != zero */
13389                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
13390                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, non_zero_bb);
13391
13392                                 //size is zero, so result is NULL
13393                                 MONO_EMIT_NEW_PCONST (cfg, alloc_ptr, NULL);
13394                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
13395
13396                                 MONO_START_BB (cfg, non_zero_bb);
13397                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
13398                                 ins->dreg = alloc_ptr;
13399                                 ins->sreg1 = sp [0]->dreg;
13400                                 ins->type = STACK_PTR;
13401                                 MONO_ADD_INS (cfg->cbb, ins);
13402
13403                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
13404                                 if (init_locals)
13405                                         ins->flags |= MONO_INST_INIT;
13406
13407                                 MONO_START_BB (cfg, end_bb);
13408                                 EMIT_NEW_UNALU (cfg, ins, OP_MOVE, alloc_preg (cfg), alloc_ptr);
13409                                 ins->type = STACK_PTR;
13410
13411                                 *sp++ = ins;
13412                                 ip += 2;
13413                                 break;
13414                         }
13415                         case CEE_ENDFILTER: {
13416                                 MonoExceptionClause *clause, *nearest;
13417                                 int cc;
13418
13419                                 CHECK_STACK (1);
13420                                 --sp;
13421                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
13422                                         UNVERIFIED;
13423                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
13424                                 ins->sreg1 = (*sp)->dreg;
13425                                 MONO_ADD_INS (cfg->cbb, ins);
13426                                 start_new_bblock = 1;
13427                                 ip += 2;
13428
13429                                 nearest = NULL;
13430                                 for (cc = 0; cc < header->num_clauses; ++cc) {
13431                                         clause = &header->clauses [cc];
13432                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
13433                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
13434                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset)))
13435                                                 nearest = clause;
13436                                 }
13437                                 g_assert (nearest);
13438                                 if ((ip - header->code) != nearest->handler_offset)
13439                                         UNVERIFIED;
13440
13441                                 break;
13442                         }
13443                         case CEE_UNALIGNED_:
13444                                 ins_flag |= MONO_INST_UNALIGNED;
13445                                 /* FIXME: record alignment? we can assume 1 for now */
13446                                 CHECK_OPSIZE (3);
13447                                 ip += 3;
13448                                 break;
13449                         case CEE_VOLATILE_:
13450                                 ins_flag |= MONO_INST_VOLATILE;
13451                                 ip += 2;
13452                                 break;
13453                         case CEE_TAIL_:
13454                                 ins_flag   |= MONO_INST_TAILCALL;
13455                                 cfg->flags |= MONO_CFG_HAS_TAIL;
13456                                 /* Can't inline tail calls at this time */
13457                                 inline_costs += 100000;
13458                                 ip += 2;
13459                                 break;
13460                         case CEE_INITOBJ:
13461                                 CHECK_STACK (1);
13462                                 --sp;
13463                                 CHECK_OPSIZE (6);
13464                                 token = read32 (ip + 2);
13465                                 klass = mini_get_class (method, token, generic_context);
13466                                 CHECK_TYPELOAD (klass);
13467                                 if (generic_class_is_reference_type (cfg, klass))
13468                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
13469                                 else
13470                                         mini_emit_initobj (cfg, *sp, NULL, klass);
13471                                 ip += 6;
13472                                 inline_costs += 1;
13473                                 break;
13474                         case CEE_CONSTRAINED_:
13475                                 CHECK_OPSIZE (6);
13476                                 token = read32 (ip + 2);
13477                                 constrained_class = mini_get_class (method, token, generic_context);
13478                                 CHECK_TYPELOAD (constrained_class);
13479                                 ip += 6;
13480                                 break;
13481                         case CEE_CPBLK:
13482                         case CEE_INITBLK: {
13483                                 MonoInst *iargs [3];
13484                                 CHECK_STACK (3);
13485                                 sp -= 3;
13486
13487                                 /* Skip optimized paths for volatile operations. */
13488                                 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)) {
13489                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
13490                                 } 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)) {
13491                                         /* emit_memset only works when val == 0 */
13492                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
13493                                 } else {
13494                                         MonoInst *call;
13495                                         iargs [0] = sp [0];
13496                                         iargs [1] = sp [1];
13497                                         iargs [2] = sp [2];
13498                                         if (ip [1] == CEE_CPBLK) {
13499                                                 /*
13500                                                  * FIXME: It's unclear whether we should be emitting both the acquire
13501                                                  * and release barriers for cpblk. It is technically both a load and
13502                                                  * store operation, so it seems like that's the sensible thing to do.
13503                                                  *
13504                                                  * FIXME: We emit full barriers on both sides of the operation for
13505                                                  * simplicity. We should have a separate atomic memcpy method instead.
13506                                                  */
13507                                                 MonoMethod *memcpy_method = get_memcpy_method ();
13508
13509                                                 if (ins_flag & MONO_INST_VOLATILE)
13510                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
13511
13512                                                 call = mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
13513                                                 call->flags |= ins_flag;
13514
13515                                                 if (ins_flag & MONO_INST_VOLATILE)
13516                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
13517                                         } else {
13518                                                 MonoMethod *memset_method = get_memset_method ();
13519                                                 if (ins_flag & MONO_INST_VOLATILE) {
13520                                                         /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
13521                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
13522                                                 }
13523                                                 call = mono_emit_method_call (cfg, memset_method, iargs, NULL);
13524                                                 call->flags |= ins_flag;
13525                                         }
13526                                 }
13527                                 ip += 2;
13528                                 ins_flag = 0;
13529                                 inline_costs += 1;
13530                                 break;
13531                         }
13532                         case CEE_NO_:
13533                                 CHECK_OPSIZE (3);
13534                                 if (ip [2] & 0x1)
13535                                         ins_flag |= MONO_INST_NOTYPECHECK;
13536                                 if (ip [2] & 0x2)
13537                                         ins_flag |= MONO_INST_NORANGECHECK;
13538                                 /* we ignore the no-nullcheck for now since we
13539                                  * really do it explicitly only when doing callvirt->call
13540                                  */
13541                                 ip += 3;
13542                                 break;
13543                         case CEE_RETHROW: {
13544                                 MonoInst *load;
13545                                 int handler_offset = -1;
13546
13547                                 for (i = 0; i < header->num_clauses; ++i) {
13548                                         MonoExceptionClause *clause = &header->clauses [i];
13549                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
13550                                                 handler_offset = clause->handler_offset;
13551                                                 break;
13552                                         }
13553                                 }
13554
13555                                 cfg->cbb->flags |= BB_EXCEPTION_UNSAFE;
13556
13557                                 if (handler_offset == -1)
13558                                         UNVERIFIED;
13559
13560                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
13561                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
13562                                 ins->sreg1 = load->dreg;
13563                                 MONO_ADD_INS (cfg->cbb, ins);
13564
13565                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
13566                                 MONO_ADD_INS (cfg->cbb, ins);
13567
13568                                 sp = stack_start;
13569                                 link_bblock (cfg, cfg->cbb, end_bblock);
13570                                 start_new_bblock = 1;
13571                                 ip += 2;
13572                                 break;
13573                         }
13574                         case CEE_SIZEOF: {
13575                                 guint32 val;
13576                                 int ialign;
13577
13578                                 CHECK_STACK_OVF (1);
13579                                 CHECK_OPSIZE (6);
13580                                 token = read32 (ip + 2);
13581                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !image_is_dynamic (method->klass->image) && !generic_context) {
13582                                         MonoType *type = mono_type_create_from_typespec_checked (image, token, &cfg->error);
13583                                         CHECK_CFG_ERROR;
13584
13585                                         val = mono_type_size (type, &ialign);
13586                                 } else {
13587                                         MonoClass *klass = mini_get_class (method, token, generic_context);
13588                                         CHECK_TYPELOAD (klass);
13589
13590                                         val = mono_type_size (&klass->byval_arg, &ialign);
13591
13592                                         if (mini_is_gsharedvt_klass (klass))
13593                                                 GSHAREDVT_FAILURE (*ip);
13594                                 }
13595                                 EMIT_NEW_ICONST (cfg, ins, val);
13596                                 *sp++= ins;
13597                                 ip += 6;
13598                                 break;
13599                         }
13600                         case CEE_REFANYTYPE: {
13601                                 MonoInst *src_var, *src;
13602
13603                                 GSHAREDVT_FAILURE (*ip);
13604
13605                                 CHECK_STACK (1);
13606                                 --sp;
13607
13608                                 // FIXME:
13609                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
13610                                 if (!src_var)
13611                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
13612                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
13613                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type));
13614                                 *sp++ = ins;
13615                                 ip += 2;
13616                                 break;
13617                         }
13618                         case CEE_READONLY_:
13619                                 readonly = TRUE;
13620                                 ip += 2;
13621                                 break;
13622
13623                         case CEE_UNUSED56:
13624                         case CEE_UNUSED57:
13625                         case CEE_UNUSED70:
13626                         case CEE_UNUSED:
13627                         case CEE_UNUSED99:
13628                                 UNVERIFIED;
13629                                 
13630                         default:
13631                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
13632                                 UNVERIFIED;
13633                         }
13634                         break;
13635                 }
13636                 case CEE_UNUSED58:
13637                 case CEE_UNUSED1:
13638                         UNVERIFIED;
13639
13640                 default:
13641                         g_warning ("opcode 0x%02x not handled", *ip);
13642                         UNVERIFIED;
13643                 }
13644         }
13645         if (start_new_bblock != 1)
13646                 UNVERIFIED;
13647
13648         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
13649         if (cfg->cbb->next_bb) {
13650                 /* This could already be set because of inlining, #693905 */
13651                 MonoBasicBlock *bb = cfg->cbb;
13652
13653                 while (bb->next_bb)
13654                         bb = bb->next_bb;
13655                 bb->next_bb = end_bblock;
13656         } else {
13657                 cfg->cbb->next_bb = end_bblock;
13658         }
13659
13660         if (cfg->method == method && cfg->domainvar) {
13661                 MonoInst *store;
13662                 MonoInst *get_domain;
13663
13664                 cfg->cbb = init_localsbb;
13665
13666                 if ((get_domain = mono_get_domain_intrinsic (cfg))) {
13667                         MONO_ADD_INS (cfg->cbb, get_domain);
13668                 } else {
13669                         get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
13670                 }
13671                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
13672                 MONO_ADD_INS (cfg->cbb, store);
13673         }
13674
13675 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
13676         if (cfg->compile_aot)
13677                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
13678                 mono_get_got_var (cfg);
13679 #endif
13680
13681         if (cfg->method == method && cfg->got_var)
13682                 mono_emit_load_got_addr (cfg);
13683
13684         if (init_localsbb) {
13685                 cfg->cbb = init_localsbb;
13686                 cfg->ip = NULL;
13687                 for (i = 0; i < header->num_locals; ++i) {
13688                         emit_init_local (cfg, i, header->locals [i], init_locals);
13689                 }
13690         }
13691
13692         if (cfg->init_ref_vars && cfg->method == method) {
13693                 /* Emit initialization for ref vars */
13694                 // FIXME: Avoid duplication initialization for IL locals.
13695                 for (i = 0; i < cfg->num_varinfo; ++i) {
13696                         MonoInst *ins = cfg->varinfo [i];
13697
13698                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
13699                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
13700                 }
13701         }
13702
13703         if (cfg->lmf_var && cfg->method == method && !cfg->llvm_only) {
13704                 cfg->cbb = init_localsbb;
13705                 emit_push_lmf (cfg);
13706         }
13707
13708         cfg->cbb = init_localsbb;
13709         emit_instrumentation_call (cfg, mono_profiler_method_enter);
13710
13711         if (seq_points) {
13712                 MonoBasicBlock *bb;
13713
13714                 /*
13715                  * Make seq points at backward branch targets interruptable.
13716                  */
13717                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
13718                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
13719                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
13720         }
13721
13722         /* Add a sequence point for method entry/exit events */
13723         if (seq_points && cfg->gen_sdb_seq_points) {
13724                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
13725                 MONO_ADD_INS (init_localsbb, ins);
13726                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
13727                 MONO_ADD_INS (cfg->bb_exit, ins);
13728         }
13729
13730         /*
13731          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
13732          * the code they refer to was dead (#11880).
13733          */
13734         if (sym_seq_points) {
13735                 for (i = 0; i < header->code_size; ++i) {
13736                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
13737                                 MonoInst *ins;
13738
13739                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
13740                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
13741                         }
13742                 }
13743         }
13744
13745         cfg->ip = NULL;
13746
13747         if (cfg->method == method) {
13748                 MonoBasicBlock *bb;
13749                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13750                         if (bb == cfg->bb_init)
13751                                 bb->region = -1;
13752                         else
13753                                 bb->region = mono_find_block_region (cfg, bb->real_offset);
13754                         if (cfg->spvars)
13755                                 mono_create_spvar_for_region (cfg, bb->region);
13756                         if (cfg->verbose_level > 2)
13757                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
13758                 }
13759         } else {
13760                 MonoBasicBlock *bb;
13761                 /* get_most_deep_clause () in mini-llvm.c depends on this for inlined bblocks */
13762                 for (bb = start_bblock; bb != end_bblock; bb  = bb->next_bb) {
13763                         bb->real_offset = inline_offset;
13764                 }
13765         }
13766
13767         if (inline_costs < 0) {
13768                 char *mname;
13769
13770                 /* Method is too large */
13771                 mname = mono_method_full_name (method, TRUE);
13772                 mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Method %s is too complex.", mname));
13773                 g_free (mname);
13774         }
13775
13776         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
13777                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
13778
13779         goto cleanup;
13780
13781 mono_error_exit:
13782         g_assert (!mono_error_ok (&cfg->error));
13783         goto cleanup;
13784  
13785  exception_exit:
13786         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
13787         goto cleanup;
13788
13789  unverified:
13790         set_exception_type_from_invalid_il (cfg, method, ip);
13791         goto cleanup;
13792
13793  cleanup:
13794         g_slist_free (class_inits);
13795         mono_basic_block_free (original_bb);
13796         cfg->dont_inline = g_list_remove (cfg->dont_inline, method);
13797         if (cfg->exception_type)
13798                 return -1;
13799         else
13800                 return inline_costs;
13801 }
13802
13803 static int
13804 store_membase_reg_to_store_membase_imm (int opcode)
13805 {
13806         switch (opcode) {
13807         case OP_STORE_MEMBASE_REG:
13808                 return OP_STORE_MEMBASE_IMM;
13809         case OP_STOREI1_MEMBASE_REG:
13810                 return OP_STOREI1_MEMBASE_IMM;
13811         case OP_STOREI2_MEMBASE_REG:
13812                 return OP_STOREI2_MEMBASE_IMM;
13813         case OP_STOREI4_MEMBASE_REG:
13814                 return OP_STOREI4_MEMBASE_IMM;
13815         case OP_STOREI8_MEMBASE_REG:
13816                 return OP_STOREI8_MEMBASE_IMM;
13817         default:
13818                 g_assert_not_reached ();
13819         }
13820
13821         return -1;
13822 }               
13823
13824 int
13825 mono_op_to_op_imm (int opcode)
13826 {
13827         switch (opcode) {
13828         case OP_IADD:
13829                 return OP_IADD_IMM;
13830         case OP_ISUB:
13831                 return OP_ISUB_IMM;
13832         case OP_IDIV:
13833                 return OP_IDIV_IMM;
13834         case OP_IDIV_UN:
13835                 return OP_IDIV_UN_IMM;
13836         case OP_IREM:
13837                 return OP_IREM_IMM;
13838         case OP_IREM_UN:
13839                 return OP_IREM_UN_IMM;
13840         case OP_IMUL:
13841                 return OP_IMUL_IMM;
13842         case OP_IAND:
13843                 return OP_IAND_IMM;
13844         case OP_IOR:
13845                 return OP_IOR_IMM;
13846         case OP_IXOR:
13847                 return OP_IXOR_IMM;
13848         case OP_ISHL:
13849                 return OP_ISHL_IMM;
13850         case OP_ISHR:
13851                 return OP_ISHR_IMM;
13852         case OP_ISHR_UN:
13853                 return OP_ISHR_UN_IMM;
13854
13855         case OP_LADD:
13856                 return OP_LADD_IMM;
13857         case OP_LSUB:
13858                 return OP_LSUB_IMM;
13859         case OP_LAND:
13860                 return OP_LAND_IMM;
13861         case OP_LOR:
13862                 return OP_LOR_IMM;
13863         case OP_LXOR:
13864                 return OP_LXOR_IMM;
13865         case OP_LSHL:
13866                 return OP_LSHL_IMM;
13867         case OP_LSHR:
13868                 return OP_LSHR_IMM;
13869         case OP_LSHR_UN:
13870                 return OP_LSHR_UN_IMM;
13871 #if SIZEOF_REGISTER == 8
13872         case OP_LREM:
13873                 return OP_LREM_IMM;
13874 #endif
13875
13876         case OP_COMPARE:
13877                 return OP_COMPARE_IMM;
13878         case OP_ICOMPARE:
13879                 return OP_ICOMPARE_IMM;
13880         case OP_LCOMPARE:
13881                 return OP_LCOMPARE_IMM;
13882
13883         case OP_STORE_MEMBASE_REG:
13884                 return OP_STORE_MEMBASE_IMM;
13885         case OP_STOREI1_MEMBASE_REG:
13886                 return OP_STOREI1_MEMBASE_IMM;
13887         case OP_STOREI2_MEMBASE_REG:
13888                 return OP_STOREI2_MEMBASE_IMM;
13889         case OP_STOREI4_MEMBASE_REG:
13890                 return OP_STOREI4_MEMBASE_IMM;
13891
13892 #if defined(TARGET_X86) || defined (TARGET_AMD64)
13893         case OP_X86_PUSH:
13894                 return OP_X86_PUSH_IMM;
13895         case OP_X86_COMPARE_MEMBASE_REG:
13896                 return OP_X86_COMPARE_MEMBASE_IMM;
13897 #endif
13898 #if defined(TARGET_AMD64)
13899         case OP_AMD64_ICOMPARE_MEMBASE_REG:
13900                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13901 #endif
13902         case OP_VOIDCALL_REG:
13903                 return OP_VOIDCALL;
13904         case OP_CALL_REG:
13905                 return OP_CALL;
13906         case OP_LCALL_REG:
13907                 return OP_LCALL;
13908         case OP_FCALL_REG:
13909                 return OP_FCALL;
13910         case OP_LOCALLOC:
13911                 return OP_LOCALLOC_IMM;
13912         }
13913
13914         return -1;
13915 }
13916
13917 static int
13918 ldind_to_load_membase (int opcode)
13919 {
13920         switch (opcode) {
13921         case CEE_LDIND_I1:
13922                 return OP_LOADI1_MEMBASE;
13923         case CEE_LDIND_U1:
13924                 return OP_LOADU1_MEMBASE;
13925         case CEE_LDIND_I2:
13926                 return OP_LOADI2_MEMBASE;
13927         case CEE_LDIND_U2:
13928                 return OP_LOADU2_MEMBASE;
13929         case CEE_LDIND_I4:
13930                 return OP_LOADI4_MEMBASE;
13931         case CEE_LDIND_U4:
13932                 return OP_LOADU4_MEMBASE;
13933         case CEE_LDIND_I:
13934                 return OP_LOAD_MEMBASE;
13935         case CEE_LDIND_REF:
13936                 return OP_LOAD_MEMBASE;
13937         case CEE_LDIND_I8:
13938                 return OP_LOADI8_MEMBASE;
13939         case CEE_LDIND_R4:
13940                 return OP_LOADR4_MEMBASE;
13941         case CEE_LDIND_R8:
13942                 return OP_LOADR8_MEMBASE;
13943         default:
13944                 g_assert_not_reached ();
13945         }
13946
13947         return -1;
13948 }
13949
13950 static int
13951 stind_to_store_membase (int opcode)
13952 {
13953         switch (opcode) {
13954         case CEE_STIND_I1:
13955                 return OP_STOREI1_MEMBASE_REG;
13956         case CEE_STIND_I2:
13957                 return OP_STOREI2_MEMBASE_REG;
13958         case CEE_STIND_I4:
13959                 return OP_STOREI4_MEMBASE_REG;
13960         case CEE_STIND_I:
13961         case CEE_STIND_REF:
13962                 return OP_STORE_MEMBASE_REG;
13963         case CEE_STIND_I8:
13964                 return OP_STOREI8_MEMBASE_REG;
13965         case CEE_STIND_R4:
13966                 return OP_STORER4_MEMBASE_REG;
13967         case CEE_STIND_R8:
13968                 return OP_STORER8_MEMBASE_REG;
13969         default:
13970                 g_assert_not_reached ();
13971         }
13972
13973         return -1;
13974 }
13975
13976 int
13977 mono_load_membase_to_load_mem (int opcode)
13978 {
13979         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
13980 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13981         switch (opcode) {
13982         case OP_LOAD_MEMBASE:
13983                 return OP_LOAD_MEM;
13984         case OP_LOADU1_MEMBASE:
13985                 return OP_LOADU1_MEM;
13986         case OP_LOADU2_MEMBASE:
13987                 return OP_LOADU2_MEM;
13988         case OP_LOADI4_MEMBASE:
13989                 return OP_LOADI4_MEM;
13990         case OP_LOADU4_MEMBASE:
13991                 return OP_LOADU4_MEM;
13992 #if SIZEOF_REGISTER == 8
13993         case OP_LOADI8_MEMBASE:
13994                 return OP_LOADI8_MEM;
13995 #endif
13996         }
13997 #endif
13998
13999         return -1;
14000 }
14001
14002 static inline int
14003 op_to_op_dest_membase (int store_opcode, int opcode)
14004 {
14005 #if defined(TARGET_X86)
14006         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
14007                 return -1;
14008
14009         switch (opcode) {
14010         case OP_IADD:
14011                 return OP_X86_ADD_MEMBASE_REG;
14012         case OP_ISUB:
14013                 return OP_X86_SUB_MEMBASE_REG;
14014         case OP_IAND:
14015                 return OP_X86_AND_MEMBASE_REG;
14016         case OP_IOR:
14017                 return OP_X86_OR_MEMBASE_REG;
14018         case OP_IXOR:
14019                 return OP_X86_XOR_MEMBASE_REG;
14020         case OP_ADD_IMM:
14021         case OP_IADD_IMM:
14022                 return OP_X86_ADD_MEMBASE_IMM;
14023         case OP_SUB_IMM:
14024         case OP_ISUB_IMM:
14025                 return OP_X86_SUB_MEMBASE_IMM;
14026         case OP_AND_IMM:
14027         case OP_IAND_IMM:
14028                 return OP_X86_AND_MEMBASE_IMM;
14029         case OP_OR_IMM:
14030         case OP_IOR_IMM:
14031                 return OP_X86_OR_MEMBASE_IMM;
14032         case OP_XOR_IMM:
14033         case OP_IXOR_IMM:
14034                 return OP_X86_XOR_MEMBASE_IMM;
14035         case OP_MOVE:
14036                 return OP_NOP;
14037         }
14038 #endif
14039
14040 #if defined(TARGET_AMD64)
14041         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
14042                 return -1;
14043
14044         switch (opcode) {
14045         case OP_IADD:
14046                 return OP_X86_ADD_MEMBASE_REG;
14047         case OP_ISUB:
14048                 return OP_X86_SUB_MEMBASE_REG;
14049         case OP_IAND:
14050                 return OP_X86_AND_MEMBASE_REG;
14051         case OP_IOR:
14052                 return OP_X86_OR_MEMBASE_REG;
14053         case OP_IXOR:
14054                 return OP_X86_XOR_MEMBASE_REG;
14055         case OP_IADD_IMM:
14056                 return OP_X86_ADD_MEMBASE_IMM;
14057         case OP_ISUB_IMM:
14058                 return OP_X86_SUB_MEMBASE_IMM;
14059         case OP_IAND_IMM:
14060                 return OP_X86_AND_MEMBASE_IMM;
14061         case OP_IOR_IMM:
14062                 return OP_X86_OR_MEMBASE_IMM;
14063         case OP_IXOR_IMM:
14064                 return OP_X86_XOR_MEMBASE_IMM;
14065         case OP_LADD:
14066                 return OP_AMD64_ADD_MEMBASE_REG;
14067         case OP_LSUB:
14068                 return OP_AMD64_SUB_MEMBASE_REG;
14069         case OP_LAND:
14070                 return OP_AMD64_AND_MEMBASE_REG;
14071         case OP_LOR:
14072                 return OP_AMD64_OR_MEMBASE_REG;
14073         case OP_LXOR:
14074                 return OP_AMD64_XOR_MEMBASE_REG;
14075         case OP_ADD_IMM:
14076         case OP_LADD_IMM:
14077                 return OP_AMD64_ADD_MEMBASE_IMM;
14078         case OP_SUB_IMM:
14079         case OP_LSUB_IMM:
14080                 return OP_AMD64_SUB_MEMBASE_IMM;
14081         case OP_AND_IMM:
14082         case OP_LAND_IMM:
14083                 return OP_AMD64_AND_MEMBASE_IMM;
14084         case OP_OR_IMM:
14085         case OP_LOR_IMM:
14086                 return OP_AMD64_OR_MEMBASE_IMM;
14087         case OP_XOR_IMM:
14088         case OP_LXOR_IMM:
14089                 return OP_AMD64_XOR_MEMBASE_IMM;
14090         case OP_MOVE:
14091                 return OP_NOP;
14092         }
14093 #endif
14094
14095         return -1;
14096 }
14097
14098 static inline int
14099 op_to_op_store_membase (int store_opcode, int opcode)
14100 {
14101 #if defined(TARGET_X86) || defined(TARGET_AMD64)
14102         switch (opcode) {
14103         case OP_ICEQ:
14104                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
14105                         return OP_X86_SETEQ_MEMBASE;
14106         case OP_CNE:
14107                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
14108                         return OP_X86_SETNE_MEMBASE;
14109         }
14110 #endif
14111
14112         return -1;
14113 }
14114
14115 static inline int
14116 op_to_op_src1_membase (MonoCompile *cfg, int load_opcode, int opcode)
14117 {
14118 #ifdef TARGET_X86
14119         /* FIXME: This has sign extension issues */
14120         /*
14121         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
14122                 return OP_X86_COMPARE_MEMBASE8_IMM;
14123         */
14124
14125         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
14126                 return -1;
14127
14128         switch (opcode) {
14129         case OP_X86_PUSH:
14130                 return OP_X86_PUSH_MEMBASE;
14131         case OP_COMPARE_IMM:
14132         case OP_ICOMPARE_IMM:
14133                 return OP_X86_COMPARE_MEMBASE_IMM;
14134         case OP_COMPARE:
14135         case OP_ICOMPARE:
14136                 return OP_X86_COMPARE_MEMBASE_REG;
14137         }
14138 #endif
14139
14140 #ifdef TARGET_AMD64
14141         /* FIXME: This has sign extension issues */
14142         /*
14143         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
14144                 return OP_X86_COMPARE_MEMBASE8_IMM;
14145         */
14146
14147         switch (opcode) {
14148         case OP_X86_PUSH:
14149                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
14150                         return OP_X86_PUSH_MEMBASE;
14151                 break;
14152                 /* FIXME: This only works for 32 bit immediates
14153         case OP_COMPARE_IMM:
14154         case OP_LCOMPARE_IMM:
14155                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
14156                         return OP_AMD64_COMPARE_MEMBASE_IMM;
14157                 */
14158         case OP_ICOMPARE_IMM:
14159                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
14160                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
14161                 break;
14162         case OP_COMPARE:
14163         case OP_LCOMPARE:
14164                 if (cfg->backend->ilp32 && load_opcode == OP_LOAD_MEMBASE)
14165                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
14166                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
14167                         return OP_AMD64_COMPARE_MEMBASE_REG;
14168                 break;
14169         case OP_ICOMPARE:
14170                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
14171                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
14172                 break;
14173         }
14174 #endif
14175
14176         return -1;
14177 }
14178
14179 static inline int
14180 op_to_op_src2_membase (MonoCompile *cfg, int load_opcode, int opcode)
14181 {
14182 #ifdef TARGET_X86
14183         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
14184                 return -1;
14185         
14186         switch (opcode) {
14187         case OP_COMPARE:
14188         case OP_ICOMPARE:
14189                 return OP_X86_COMPARE_REG_MEMBASE;
14190         case OP_IADD:
14191                 return OP_X86_ADD_REG_MEMBASE;
14192         case OP_ISUB:
14193                 return OP_X86_SUB_REG_MEMBASE;
14194         case OP_IAND:
14195                 return OP_X86_AND_REG_MEMBASE;
14196         case OP_IOR:
14197                 return OP_X86_OR_REG_MEMBASE;
14198         case OP_IXOR:
14199                 return OP_X86_XOR_REG_MEMBASE;
14200         }
14201 #endif
14202
14203 #ifdef TARGET_AMD64
14204         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && cfg->backend->ilp32)) {
14205                 switch (opcode) {
14206                 case OP_ICOMPARE:
14207                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
14208                 case OP_IADD:
14209                         return OP_X86_ADD_REG_MEMBASE;
14210                 case OP_ISUB:
14211                         return OP_X86_SUB_REG_MEMBASE;
14212                 case OP_IAND:
14213                         return OP_X86_AND_REG_MEMBASE;
14214                 case OP_IOR:
14215                         return OP_X86_OR_REG_MEMBASE;
14216                 case OP_IXOR:
14217                         return OP_X86_XOR_REG_MEMBASE;
14218                 }
14219         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32)) {
14220                 switch (opcode) {
14221                 case OP_COMPARE:
14222                 case OP_LCOMPARE:
14223                         return OP_AMD64_COMPARE_REG_MEMBASE;
14224                 case OP_LADD:
14225                         return OP_AMD64_ADD_REG_MEMBASE;
14226                 case OP_LSUB:
14227                         return OP_AMD64_SUB_REG_MEMBASE;
14228                 case OP_LAND:
14229                         return OP_AMD64_AND_REG_MEMBASE;
14230                 case OP_LOR:
14231                         return OP_AMD64_OR_REG_MEMBASE;
14232                 case OP_LXOR:
14233                         return OP_AMD64_XOR_REG_MEMBASE;
14234                 }
14235         }
14236 #endif
14237
14238         return -1;
14239 }
14240
14241 int
14242 mono_op_to_op_imm_noemul (int opcode)
14243 {
14244         switch (opcode) {
14245 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
14246         case OP_LSHR:
14247         case OP_LSHL:
14248         case OP_LSHR_UN:
14249                 return -1;
14250 #endif
14251 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
14252         case OP_IDIV:
14253         case OP_IDIV_UN:
14254         case OP_IREM:
14255         case OP_IREM_UN:
14256                 return -1;
14257 #endif
14258 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
14259         case OP_IMUL:
14260                 return -1;
14261 #endif
14262         default:
14263                 return mono_op_to_op_imm (opcode);
14264         }
14265 }
14266
14267 /**
14268  * mono_handle_global_vregs:
14269  *
14270  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
14271  * for them.
14272  */
14273 void
14274 mono_handle_global_vregs (MonoCompile *cfg)
14275 {
14276         gint32 *vreg_to_bb;
14277         MonoBasicBlock *bb;
14278         int i, pos;
14279
14280         vreg_to_bb = (gint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
14281
14282 #ifdef MONO_ARCH_SIMD_INTRINSICS
14283         if (cfg->uses_simd_intrinsics)
14284                 mono_simd_simplify_indirection (cfg);
14285 #endif
14286
14287         /* Find local vregs used in more than one bb */
14288         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
14289                 MonoInst *ins = bb->code;       
14290                 int block_num = bb->block_num;
14291
14292                 if (cfg->verbose_level > 2)
14293                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
14294
14295                 cfg->cbb = bb;
14296                 for (; ins; ins = ins->next) {
14297                         const char *spec = INS_INFO (ins->opcode);
14298                         int regtype = 0, regindex;
14299                         gint32 prev_bb;
14300
14301                         if (G_UNLIKELY (cfg->verbose_level > 2))
14302                                 mono_print_ins (ins);
14303
14304                         g_assert (ins->opcode >= MONO_CEE_LAST);
14305
14306                         for (regindex = 0; regindex < 4; regindex ++) {
14307                                 int vreg = 0;
14308
14309                                 if (regindex == 0) {
14310                                         regtype = spec [MONO_INST_DEST];
14311                                         if (regtype == ' ')
14312                                                 continue;
14313                                         vreg = ins->dreg;
14314                                 } else if (regindex == 1) {
14315                                         regtype = spec [MONO_INST_SRC1];
14316                                         if (regtype == ' ')
14317                                                 continue;
14318                                         vreg = ins->sreg1;
14319                                 } else if (regindex == 2) {
14320                                         regtype = spec [MONO_INST_SRC2];
14321                                         if (regtype == ' ')
14322                                                 continue;
14323                                         vreg = ins->sreg2;
14324                                 } else if (regindex == 3) {
14325                                         regtype = spec [MONO_INST_SRC3];
14326                                         if (regtype == ' ')
14327                                                 continue;
14328                                         vreg = ins->sreg3;
14329                                 }
14330
14331 #if SIZEOF_REGISTER == 4
14332                                 /* In the LLVM case, the long opcodes are not decomposed */
14333                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
14334                                         /*
14335                                          * Since some instructions reference the original long vreg,
14336                                          * and some reference the two component vregs, it is quite hard
14337                                          * to determine when it needs to be global. So be conservative.
14338                                          */
14339                                         if (!get_vreg_to_inst (cfg, vreg)) {
14340                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
14341
14342                                                 if (cfg->verbose_level > 2)
14343                                                         printf ("LONG VREG R%d made global.\n", vreg);
14344                                         }
14345
14346                                         /*
14347                                          * Make the component vregs volatile since the optimizations can
14348                                          * get confused otherwise.
14349                                          */
14350                                         get_vreg_to_inst (cfg, MONO_LVREG_LS (vreg))->flags |= MONO_INST_VOLATILE;
14351                                         get_vreg_to_inst (cfg, MONO_LVREG_MS (vreg))->flags |= MONO_INST_VOLATILE;
14352                                 }
14353 #endif
14354
14355                                 g_assert (vreg != -1);
14356
14357                                 prev_bb = vreg_to_bb [vreg];
14358                                 if (prev_bb == 0) {
14359                                         /* 0 is a valid block num */
14360                                         vreg_to_bb [vreg] = block_num + 1;
14361                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
14362                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
14363                                                 continue;
14364
14365                                         if (!get_vreg_to_inst (cfg, vreg)) {
14366                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14367                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
14368
14369                                                 switch (regtype) {
14370                                                 case 'i':
14371                                                         if (vreg_is_ref (cfg, vreg))
14372                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
14373                                                         else
14374                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
14375                                                         break;
14376                                                 case 'l':
14377                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
14378                                                         break;
14379                                                 case 'f':
14380                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
14381                                                         break;
14382                                                 case 'v':
14383                                                 case 'x':
14384                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
14385                                                         break;
14386                                                 default:
14387                                                         g_assert_not_reached ();
14388                                                 }
14389                                         }
14390
14391                                         /* Flag as having been used in more than one bb */
14392                                         vreg_to_bb [vreg] = -1;
14393                                 }
14394                         }
14395                 }
14396         }
14397
14398         /* If a variable is used in only one bblock, convert it into a local vreg */
14399         for (i = 0; i < cfg->num_varinfo; i++) {
14400                 MonoInst *var = cfg->varinfo [i];
14401                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
14402
14403                 switch (var->type) {
14404                 case STACK_I4:
14405                 case STACK_OBJ:
14406                 case STACK_PTR:
14407                 case STACK_MP:
14408                 case STACK_VTYPE:
14409 #if SIZEOF_REGISTER == 8
14410                 case STACK_I8:
14411 #endif
14412 #if !defined(TARGET_X86)
14413                 /* Enabling this screws up the fp stack on x86 */
14414                 case STACK_R8:
14415 #endif
14416                         if (mono_arch_is_soft_float ())
14417                                 break;
14418
14419                         /*
14420                         if (var->type == STACK_VTYPE && cfg->gsharedvt && mini_is_gsharedvt_variable_type (var->inst_vtype))
14421                                 break;
14422                         */
14423
14424                         /* Arguments are implicitly global */
14425                         /* Putting R4 vars into registers doesn't work currently */
14426                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
14427                         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) {
14428                                 /* 
14429                                  * Make that the variable's liveness interval doesn't contain a call, since
14430                                  * that would cause the lvreg to be spilled, making the whole optimization
14431                                  * useless.
14432                                  */
14433                                 /* This is too slow for JIT compilation */
14434 #if 0
14435                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
14436                                         MonoInst *ins;
14437                                         int def_index, call_index, ins_index;
14438                                         gboolean spilled = FALSE;
14439
14440                                         def_index = -1;
14441                                         call_index = -1;
14442                                         ins_index = 0;
14443                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
14444                                                 const char *spec = INS_INFO (ins->opcode);
14445
14446                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
14447                                                         def_index = ins_index;
14448
14449                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
14450                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
14451                                                         if (call_index > def_index) {
14452                                                                 spilled = TRUE;
14453                                                                 break;
14454                                                         }
14455                                                 }
14456
14457                                                 if (MONO_IS_CALL (ins))
14458                                                         call_index = ins_index;
14459
14460                                                 ins_index ++;
14461                                         }
14462
14463                                         if (spilled)
14464                                                 break;
14465                                 }
14466 #endif
14467
14468                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14469                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
14470                                 var->flags |= MONO_INST_IS_DEAD;
14471                                 cfg->vreg_to_inst [var->dreg] = NULL;
14472                         }
14473                         break;
14474                 }
14475         }
14476
14477         /* 
14478          * Compress the varinfo and vars tables so the liveness computation is faster and
14479          * takes up less space.
14480          */
14481         pos = 0;
14482         for (i = 0; i < cfg->num_varinfo; ++i) {
14483                 MonoInst *var = cfg->varinfo [i];
14484                 if (pos < i && cfg->locals_start == i)
14485                         cfg->locals_start = pos;
14486                 if (!(var->flags & MONO_INST_IS_DEAD)) {
14487                         if (pos < i) {
14488                                 cfg->varinfo [pos] = cfg->varinfo [i];
14489                                 cfg->varinfo [pos]->inst_c0 = pos;
14490                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
14491                                 cfg->vars [pos].idx = pos;
14492 #if SIZEOF_REGISTER == 4
14493                                 if (cfg->varinfo [pos]->type == STACK_I8) {
14494                                         /* Modify the two component vars too */
14495                                         MonoInst *var1;
14496
14497                                         var1 = get_vreg_to_inst (cfg, MONO_LVREG_LS (cfg->varinfo [pos]->dreg));
14498                                         var1->inst_c0 = pos;
14499                                         var1 = get_vreg_to_inst (cfg, MONO_LVREG_MS (cfg->varinfo [pos]->dreg));
14500                                         var1->inst_c0 = pos;
14501                                 }
14502 #endif
14503                         }
14504                         pos ++;
14505                 }
14506         }
14507         cfg->num_varinfo = pos;
14508         if (cfg->locals_start > cfg->num_varinfo)
14509                 cfg->locals_start = cfg->num_varinfo;
14510 }
14511
14512 /*
14513  * mono_allocate_gsharedvt_vars:
14514  *
14515  *   Allocate variables with gsharedvt types to entries in the MonoGSharedVtMethodRuntimeInfo.entries array.
14516  * Initialize cfg->gsharedvt_vreg_to_idx with the mapping between vregs and indexes.
14517  */
14518 void
14519 mono_allocate_gsharedvt_vars (MonoCompile *cfg)
14520 {
14521         int i;
14522
14523         cfg->gsharedvt_vreg_to_idx = (int *)mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
14524
14525         for (i = 0; i < cfg->num_varinfo; ++i) {
14526                 MonoInst *ins = cfg->varinfo [i];
14527                 int idx;
14528
14529                 if (mini_is_gsharedvt_variable_type (ins->inst_vtype)) {
14530                         if (i >= cfg->locals_start) {
14531                                 /* Local */
14532                                 idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
14533                                 cfg->gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
14534                                 ins->opcode = OP_GSHAREDVT_LOCAL;
14535                                 ins->inst_imm = idx;
14536                         } else {
14537                                 /* Arg */
14538                                 cfg->gsharedvt_vreg_to_idx [ins->dreg] = -1;
14539                                 ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
14540                         }
14541                 }
14542         }
14543 }
14544
14545 /**
14546  * mono_spill_global_vars:
14547  *
14548  *   Generate spill code for variables which are not allocated to registers, 
14549  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
14550  * code is generated which could be optimized by the local optimization passes.
14551  */
14552 void
14553 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
14554 {
14555         MonoBasicBlock *bb;
14556         char spec2 [16];
14557         int orig_next_vreg;
14558         guint32 *vreg_to_lvreg;
14559         guint32 *lvregs;
14560         guint32 i, lvregs_len;
14561         gboolean dest_has_lvreg = FALSE;
14562         MonoStackType stacktypes [128];
14563         MonoInst **live_range_start, **live_range_end;
14564         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
14565
14566         *need_local_opts = FALSE;
14567
14568         memset (spec2, 0, sizeof (spec2));
14569
14570         /* FIXME: Move this function to mini.c */
14571         stacktypes ['i'] = STACK_PTR;
14572         stacktypes ['l'] = STACK_I8;
14573         stacktypes ['f'] = STACK_R8;
14574 #ifdef MONO_ARCH_SIMD_INTRINSICS
14575         stacktypes ['x'] = STACK_VTYPE;
14576 #endif
14577
14578 #if SIZEOF_REGISTER == 4
14579         /* Create MonoInsts for longs */
14580         for (i = 0; i < cfg->num_varinfo; i++) {
14581                 MonoInst *ins = cfg->varinfo [i];
14582
14583                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
14584                         switch (ins->type) {
14585                         case STACK_R8:
14586                         case STACK_I8: {
14587                                 MonoInst *tree;
14588
14589                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
14590                                         break;
14591
14592                                 g_assert (ins->opcode == OP_REGOFFSET);
14593
14594                                 tree = get_vreg_to_inst (cfg, MONO_LVREG_LS (ins->dreg));
14595                                 g_assert (tree);
14596                                 tree->opcode = OP_REGOFFSET;
14597                                 tree->inst_basereg = ins->inst_basereg;
14598                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
14599
14600                                 tree = get_vreg_to_inst (cfg, MONO_LVREG_MS (ins->dreg));
14601                                 g_assert (tree);
14602                                 tree->opcode = OP_REGOFFSET;
14603                                 tree->inst_basereg = ins->inst_basereg;
14604                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
14605                                 break;
14606                         }
14607                         default:
14608                                 break;
14609                         }
14610                 }
14611         }
14612 #endif
14613
14614         if (cfg->compute_gc_maps) {
14615                 /* registers need liveness info even for !non refs */
14616                 for (i = 0; i < cfg->num_varinfo; i++) {
14617                         MonoInst *ins = cfg->varinfo [i];
14618
14619                         if (ins->opcode == OP_REGVAR)
14620                                 ins->flags |= MONO_INST_GC_TRACK;
14621                 }
14622         }
14623                 
14624         /* FIXME: widening and truncation */
14625
14626         /*
14627          * As an optimization, when a variable allocated to the stack is first loaded into 
14628          * an lvreg, we will remember the lvreg and use it the next time instead of loading
14629          * the variable again.
14630          */
14631         orig_next_vreg = cfg->next_vreg;
14632         vreg_to_lvreg = (guint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
14633         lvregs = (guint32 *)mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
14634         lvregs_len = 0;
14635
14636         /* 
14637          * These arrays contain the first and last instructions accessing a given
14638          * variable.
14639          * Since we emit bblocks in the same order we process them here, and we
14640          * don't split live ranges, these will precisely describe the live range of
14641          * the variable, i.e. the instruction range where a valid value can be found
14642          * in the variables location.
14643          * The live range is computed using the liveness info computed by the liveness pass.
14644          * We can't use vmv->range, since that is an abstract live range, and we need
14645          * one which is instruction precise.
14646          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
14647          */
14648         /* FIXME: Only do this if debugging info is requested */
14649         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
14650         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
14651         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
14652         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
14653         
14654         /* Add spill loads/stores */
14655         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
14656                 MonoInst *ins;
14657
14658                 if (cfg->verbose_level > 2)
14659                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
14660
14661                 /* Clear vreg_to_lvreg array */
14662                 for (i = 0; i < lvregs_len; i++)
14663                         vreg_to_lvreg [lvregs [i]] = 0;
14664                 lvregs_len = 0;
14665
14666                 cfg->cbb = bb;
14667                 MONO_BB_FOR_EACH_INS (bb, ins) {
14668                         const char *spec = INS_INFO (ins->opcode);
14669                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
14670                         gboolean store, no_lvreg;
14671                         int sregs [MONO_MAX_SRC_REGS];
14672
14673                         if (G_UNLIKELY (cfg->verbose_level > 2))
14674                                 mono_print_ins (ins);
14675
14676                         if (ins->opcode == OP_NOP)
14677                                 continue;
14678
14679                         /* 
14680                          * We handle LDADDR here as well, since it can only be decomposed
14681                          * when variable addresses are known.
14682                          */
14683                         if (ins->opcode == OP_LDADDR) {
14684                                 MonoInst *var = (MonoInst *)ins->inst_p0;
14685
14686                                 if (var->opcode == OP_VTARG_ADDR) {
14687                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
14688                                         MonoInst *vtaddr = var->inst_left;
14689                                         if (vtaddr->opcode == OP_REGVAR) {
14690                                                 ins->opcode = OP_MOVE;
14691                                                 ins->sreg1 = vtaddr->dreg;
14692                                         }
14693                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
14694                                                 ins->opcode = OP_LOAD_MEMBASE;
14695                                                 ins->inst_basereg = vtaddr->inst_basereg;
14696                                                 ins->inst_offset = vtaddr->inst_offset;
14697                                         } else
14698                                                 NOT_IMPLEMENTED;
14699                                 } else if (cfg->gsharedvt && cfg->gsharedvt_vreg_to_idx [var->dreg] < 0) {
14700                                         /* gsharedvt arg passed by ref */
14701                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
14702
14703                                         ins->opcode = OP_LOAD_MEMBASE;
14704                                         ins->inst_basereg = var->inst_basereg;
14705                                         ins->inst_offset = var->inst_offset;
14706                                 } else if (cfg->gsharedvt && cfg->gsharedvt_vreg_to_idx [var->dreg]) {
14707                                         MonoInst *load, *load2, *load3;
14708                                         int idx = cfg->gsharedvt_vreg_to_idx [var->dreg] - 1;
14709                                         int reg1, reg2, reg3;
14710                                         MonoInst *info_var = cfg->gsharedvt_info_var;
14711                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
14712
14713                                         /*
14714                                          * gsharedvt local.
14715                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
14716                                          */
14717
14718                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
14719
14720                                         g_assert (info_var);
14721                                         g_assert (locals_var);
14722
14723                                         /* Mark the instruction used to compute the locals var as used */
14724                                         cfg->gsharedvt_locals_var_ins = NULL;
14725
14726                                         /* Load the offset */
14727                                         if (info_var->opcode == OP_REGOFFSET) {
14728                                                 reg1 = alloc_ireg (cfg);
14729                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
14730                                         } else if (info_var->opcode == OP_REGVAR) {
14731                                                 load = NULL;
14732                                                 reg1 = info_var->dreg;
14733                                         } else {
14734                                                 g_assert_not_reached ();
14735                                         }
14736                                         reg2 = alloc_ireg (cfg);
14737                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
14738                                         /* Load the locals area address */
14739                                         reg3 = alloc_ireg (cfg);
14740                                         if (locals_var->opcode == OP_REGOFFSET) {
14741                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
14742                                         } else if (locals_var->opcode == OP_REGVAR) {
14743                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
14744                                         } else {
14745                                                 g_assert_not_reached ();
14746                                         }
14747                                         /* Compute the address */
14748                                         ins->opcode = OP_PADD;
14749                                         ins->sreg1 = reg3;
14750                                         ins->sreg2 = reg2;
14751
14752                                         mono_bblock_insert_before_ins (bb, ins, load3);
14753                                         mono_bblock_insert_before_ins (bb, load3, load2);
14754                                         if (load)
14755                                                 mono_bblock_insert_before_ins (bb, load2, load);
14756                                 } else {
14757                                         g_assert (var->opcode == OP_REGOFFSET);
14758
14759                                         ins->opcode = OP_ADD_IMM;
14760                                         ins->sreg1 = var->inst_basereg;
14761                                         ins->inst_imm = var->inst_offset;
14762                                 }
14763
14764                                 *need_local_opts = TRUE;
14765                                 spec = INS_INFO (ins->opcode);
14766                         }
14767
14768                         if (ins->opcode < MONO_CEE_LAST) {
14769                                 mono_print_ins (ins);
14770                                 g_assert_not_reached ();
14771                         }
14772
14773                         /*
14774                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
14775                          * src register.
14776                          * FIXME:
14777                          */
14778                         if (MONO_IS_STORE_MEMBASE (ins)) {
14779                                 tmp_reg = ins->dreg;
14780                                 ins->dreg = ins->sreg2;
14781                                 ins->sreg2 = tmp_reg;
14782                                 store = TRUE;
14783
14784                                 spec2 [MONO_INST_DEST] = ' ';
14785                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14786                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14787                                 spec2 [MONO_INST_SRC3] = ' ';
14788                                 spec = spec2;
14789                         } else if (MONO_IS_STORE_MEMINDEX (ins))
14790                                 g_assert_not_reached ();
14791                         else
14792                                 store = FALSE;
14793                         no_lvreg = FALSE;
14794
14795                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
14796                                 printf ("\t %.3s %d", spec, ins->dreg);
14797                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
14798                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
14799                                         printf (" %d", sregs [srcindex]);
14800                                 printf ("\n");
14801                         }
14802
14803                         /***************/
14804                         /*    DREG     */
14805                         /***************/
14806                         regtype = spec [MONO_INST_DEST];
14807                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
14808                         prev_dreg = -1;
14809
14810                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
14811                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
14812                                 MonoInst *store_ins;
14813                                 int store_opcode;
14814                                 MonoInst *def_ins = ins;
14815                                 int dreg = ins->dreg; /* The original vreg */
14816
14817                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
14818
14819                                 if (var->opcode == OP_REGVAR) {
14820                                         ins->dreg = var->dreg;
14821                                 } 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)) {
14822                                         /* 
14823                                          * Instead of emitting a load+store, use a _membase opcode.
14824                                          */
14825                                         g_assert (var->opcode == OP_REGOFFSET);
14826                                         if (ins->opcode == OP_MOVE) {
14827                                                 NULLIFY_INS (ins);
14828                                                 def_ins = NULL;
14829                                         } else {
14830                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
14831                                                 ins->inst_basereg = var->inst_basereg;
14832                                                 ins->inst_offset = var->inst_offset;
14833                                                 ins->dreg = -1;
14834                                         }
14835                                         spec = INS_INFO (ins->opcode);
14836                                 } else {
14837                                         guint32 lvreg;
14838
14839                                         g_assert (var->opcode == OP_REGOFFSET);
14840
14841                                         prev_dreg = ins->dreg;
14842
14843                                         /* Invalidate any previous lvreg for this vreg */
14844                                         vreg_to_lvreg [ins->dreg] = 0;
14845
14846                                         lvreg = 0;
14847
14848                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
14849                                                 regtype = 'l';
14850                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
14851                                         }
14852
14853                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
14854
14855 #if SIZEOF_REGISTER != 8
14856                                         if (regtype == 'l') {
14857                                                 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));
14858                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14859                                                 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));
14860                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14861                                                 def_ins = store_ins;
14862                                         }
14863                                         else
14864 #endif
14865                                         {
14866                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
14867
14868                                                 /* Try to fuse the store into the instruction itself */
14869                                                 /* FIXME: Add more instructions */
14870                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
14871                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
14872                                                         ins->inst_imm = ins->inst_c0;
14873                                                         ins->inst_destbasereg = var->inst_basereg;
14874                                                         ins->inst_offset = var->inst_offset;
14875                                                         spec = INS_INFO (ins->opcode);
14876                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE) || (ins->opcode == OP_RMOVE))) {
14877                                                         ins->opcode = store_opcode;
14878                                                         ins->inst_destbasereg = var->inst_basereg;
14879                                                         ins->inst_offset = var->inst_offset;
14880
14881                                                         no_lvreg = TRUE;
14882
14883                                                         tmp_reg = ins->dreg;
14884                                                         ins->dreg = ins->sreg2;
14885                                                         ins->sreg2 = tmp_reg;
14886                                                         store = TRUE;
14887
14888                                                         spec2 [MONO_INST_DEST] = ' ';
14889                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14890                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14891                                                         spec2 [MONO_INST_SRC3] = ' ';
14892                                                         spec = spec2;
14893                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
14894                                                         // FIXME: The backends expect the base reg to be in inst_basereg
14895                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
14896                                                         ins->dreg = -1;
14897                                                         ins->inst_basereg = var->inst_basereg;
14898                                                         ins->inst_offset = var->inst_offset;
14899                                                         spec = INS_INFO (ins->opcode);
14900                                                 } else {
14901                                                         /* printf ("INS: "); mono_print_ins (ins); */
14902                                                         /* Create a store instruction */
14903                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
14904
14905                                                         /* Insert it after the instruction */
14906                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
14907
14908                                                         def_ins = store_ins;
14909
14910                                                         /* 
14911                                                          * We can't assign ins->dreg to var->dreg here, since the
14912                                                          * sregs could use it. So set a flag, and do it after
14913                                                          * the sregs.
14914                                                          */
14915                                                         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)))
14916                                                                 dest_has_lvreg = TRUE;
14917                                                 }
14918                                         }
14919                                 }
14920
14921                                 if (def_ins && !live_range_start [dreg]) {
14922                                         live_range_start [dreg] = def_ins;
14923                                         live_range_start_bb [dreg] = bb;
14924                                 }
14925
14926                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
14927                                         MonoInst *tmp;
14928
14929                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
14930                                         tmp->inst_c1 = dreg;
14931                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
14932                                 }
14933                         }
14934
14935                         /************/
14936                         /*  SREGS   */
14937                         /************/
14938                         num_sregs = mono_inst_get_src_registers (ins, sregs);
14939                         for (srcindex = 0; srcindex < 3; ++srcindex) {
14940                                 regtype = spec [MONO_INST_SRC1 + srcindex];
14941                                 sreg = sregs [srcindex];
14942
14943                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
14944                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
14945                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
14946                                         MonoInst *use_ins = ins;
14947                                         MonoInst *load_ins;
14948                                         guint32 load_opcode;
14949
14950                                         if (var->opcode == OP_REGVAR) {
14951                                                 sregs [srcindex] = var->dreg;
14952                                                 //mono_inst_set_src_registers (ins, sregs);
14953                                                 live_range_end [sreg] = use_ins;
14954                                                 live_range_end_bb [sreg] = bb;
14955
14956                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14957                                                         MonoInst *tmp;
14958
14959                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14960                                                         /* var->dreg is a hreg */
14961                                                         tmp->inst_c1 = sreg;
14962                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
14963                                                 }
14964
14965                                                 continue;
14966                                         }
14967
14968                                         g_assert (var->opcode == OP_REGOFFSET);
14969                                                 
14970                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
14971
14972                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
14973
14974                                         if (vreg_to_lvreg [sreg]) {
14975                                                 g_assert (vreg_to_lvreg [sreg] != -1);
14976
14977                                                 /* The variable is already loaded to an lvreg */
14978                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14979                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
14980                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
14981                                                 //mono_inst_set_src_registers (ins, sregs);
14982                                                 continue;
14983                                         }
14984
14985                                         /* Try to fuse the load into the instruction */
14986                                         if ((srcindex == 0) && (op_to_op_src1_membase (cfg, load_opcode, ins->opcode) != -1)) {
14987                                                 ins->opcode = op_to_op_src1_membase (cfg, load_opcode, ins->opcode);
14988                                                 sregs [0] = var->inst_basereg;
14989                                                 //mono_inst_set_src_registers (ins, sregs);
14990                                                 ins->inst_offset = var->inst_offset;
14991                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (cfg, load_opcode, ins->opcode) != -1)) {
14992                                                 ins->opcode = op_to_op_src2_membase (cfg, load_opcode, ins->opcode);
14993                                                 sregs [1] = var->inst_basereg;
14994                                                 //mono_inst_set_src_registers (ins, sregs);
14995                                                 ins->inst_offset = var->inst_offset;
14996                                         } else {
14997                                                 if (MONO_IS_REAL_MOVE (ins)) {
14998                                                         ins->opcode = OP_NOP;
14999                                                         sreg = ins->dreg;
15000                                                 } else {
15001                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
15002
15003                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
15004
15005                                                         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) {
15006                                                                 if (var->dreg == prev_dreg) {
15007                                                                         /*
15008                                                                          * sreg refers to the value loaded by the load
15009                                                                          * emitted below, but we need to use ins->dreg
15010                                                                          * since it refers to the store emitted earlier.
15011                                                                          */
15012                                                                         sreg = ins->dreg;
15013                                                                 }
15014                                                                 g_assert (sreg != -1);
15015                                                                 vreg_to_lvreg [var->dreg] = sreg;
15016                                                                 g_assert (lvregs_len < 1024);
15017                                                                 lvregs [lvregs_len ++] = var->dreg;
15018                                                         }
15019                                                 }
15020
15021                                                 sregs [srcindex] = sreg;
15022                                                 //mono_inst_set_src_registers (ins, sregs);
15023
15024 #if SIZEOF_REGISTER != 8
15025                                                 if (regtype == 'l') {
15026                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_MS (sreg), var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
15027                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
15028                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_LS (sreg), var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
15029                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
15030                                                         use_ins = load_ins;
15031                                                 }
15032                                                 else
15033 #endif
15034                                                 {
15035 #if SIZEOF_REGISTER == 4
15036                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
15037 #endif
15038                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
15039                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
15040                                                         use_ins = load_ins;
15041                                                 }
15042                                         }
15043
15044                                         if (var->dreg < orig_next_vreg) {
15045                                                 live_range_end [var->dreg] = use_ins;
15046                                                 live_range_end_bb [var->dreg] = bb;
15047                                         }
15048
15049                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
15050                                                 MonoInst *tmp;
15051
15052                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
15053                                                 tmp->inst_c1 = var->dreg;
15054                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
15055                                         }
15056                                 }
15057                         }
15058                         mono_inst_set_src_registers (ins, sregs);
15059
15060                         if (dest_has_lvreg) {
15061                                 g_assert (ins->dreg != -1);
15062                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
15063                                 g_assert (lvregs_len < 1024);
15064                                 lvregs [lvregs_len ++] = prev_dreg;
15065                                 dest_has_lvreg = FALSE;
15066                         }
15067
15068                         if (store) {
15069                                 tmp_reg = ins->dreg;
15070                                 ins->dreg = ins->sreg2;
15071                                 ins->sreg2 = tmp_reg;
15072                         }
15073
15074                         if (MONO_IS_CALL (ins)) {
15075                                 /* Clear vreg_to_lvreg array */
15076                                 for (i = 0; i < lvregs_len; i++)
15077                                         vreg_to_lvreg [lvregs [i]] = 0;
15078                                 lvregs_len = 0;
15079                         } else if (ins->opcode == OP_NOP) {
15080                                 ins->dreg = -1;
15081                                 MONO_INST_NULLIFY_SREGS (ins);
15082                         }
15083
15084                         if (cfg->verbose_level > 2)
15085                                 mono_print_ins_index (1, ins);
15086                 }
15087
15088                 /* Extend the live range based on the liveness info */
15089                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
15090                         for (i = 0; i < cfg->num_varinfo; i ++) {
15091                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
15092
15093                                 if (vreg_is_volatile (cfg, vi->vreg))
15094                                         /* The liveness info is incomplete */
15095                                         continue;
15096
15097                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
15098                                         /* Live from at least the first ins of this bb */
15099                                         live_range_start [vi->vreg] = bb->code;
15100                                         live_range_start_bb [vi->vreg] = bb;
15101                                 }
15102
15103                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
15104                                         /* Live at least until the last ins of this bb */
15105                                         live_range_end [vi->vreg] = bb->last_ins;
15106                                         live_range_end_bb [vi->vreg] = bb;
15107                                 }
15108                         }
15109                 }
15110         }
15111         
15112         /*
15113          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
15114          * by storing the current native offset into MonoMethodVar->live_range_start/end.
15115          */
15116         if (cfg->backend->have_liverange_ops && cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
15117                 for (i = 0; i < cfg->num_varinfo; ++i) {
15118                         int vreg = MONO_VARINFO (cfg, i)->vreg;
15119                         MonoInst *ins;
15120
15121                         if (live_range_start [vreg]) {
15122                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
15123                                 ins->inst_c0 = i;
15124                                 ins->inst_c1 = vreg;
15125                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
15126                         }
15127                         if (live_range_end [vreg]) {
15128                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
15129                                 ins->inst_c0 = i;
15130                                 ins->inst_c1 = vreg;
15131                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
15132                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
15133                                 else
15134                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
15135                         }
15136                 }
15137         }
15138
15139         if (cfg->gsharedvt_locals_var_ins) {
15140                 /* Nullify if unused */
15141                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
15142                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
15143         }
15144
15145         g_free (live_range_start);
15146         g_free (live_range_end);
15147         g_free (live_range_start_bb);
15148         g_free (live_range_end_bb);
15149 }
15150
15151 static void
15152 mono_decompose_typecheck (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins)
15153 {
15154         MonoInst *ret, *move, *source;
15155         MonoClass *klass = ins->klass;
15156         int context_used = mini_class_check_context_used (cfg, klass);
15157         int is_isinst = ins->opcode == OP_ISINST;
15158         g_assert (is_isinst || ins->opcode == OP_CASTCLASS);
15159         source = get_vreg_to_inst (cfg, ins->sreg1);
15160         if (!source || source == (MonoInst *) -1)
15161                 source = mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, ins->sreg1);
15162         g_assert (source && source != (MonoInst *) -1);
15163
15164         MonoBasicBlock *first_bb;
15165         NEW_BBLOCK (cfg, first_bb);
15166         cfg->cbb = first_bb;
15167
15168         if (!context_used && (mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || klass->is_array_special_interface)) {
15169                 if (is_isinst)
15170                         ret = emit_isinst_with_cache_nonshared (cfg, source, klass);
15171                 else
15172                         ret = emit_castclass_with_cache_nonshared (cfg, source, klass);
15173         } else if (!context_used && (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass))) {
15174                 MonoInst *iargs [1];
15175                 int costs;
15176
15177                 iargs [0] = source;
15178                 if (is_isinst) {
15179                         MonoMethod *wrapper = mono_marshal_get_isinst (klass);
15180                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), iargs, 0, 0, TRUE);
15181                 } else {
15182                         MonoMethod *wrapper = mono_marshal_get_castclass (klass);
15183                         save_cast_details (cfg, klass, source->dreg, TRUE);
15184                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), iargs, 0, 0, TRUE);
15185                         reset_cast_details (cfg);
15186                 }
15187                 g_assert (costs > 0);
15188                 ret = iargs [0];
15189         } else {
15190                 if (is_isinst)
15191                         ret = handle_isinst (cfg, klass, source, context_used);
15192                 else
15193                         ret = handle_castclass (cfg, klass, source, context_used);
15194         }
15195         EMIT_NEW_UNALU (cfg, move, OP_MOVE, ins->dreg, ret->dreg);
15196
15197         g_assert (cfg->cbb->code || first_bb->code);
15198         MonoInst *prev = ins->prev;
15199         mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
15200 }
15201
15202 void
15203 mono_decompose_typechecks (MonoCompile *cfg)
15204 {
15205         for (MonoBasicBlock *bb = cfg->bb_entry; bb; bb = bb->next_bb) {
15206                 MonoInst *ins;
15207                 MONO_BB_FOR_EACH_INS (bb, ins) {
15208                         switch (ins->opcode) {
15209                         case OP_ISINST:
15210                         case OP_CASTCLASS:
15211                                 mono_decompose_typecheck (cfg, bb, ins);
15212                                 break;
15213                         }
15214                 }
15215         }
15216 }
15217
15218
15219 /**
15220  * FIXME:
15221  * - use 'iadd' instead of 'int_add'
15222  * - handling ovf opcodes: decompose in method_to_ir.
15223  * - unify iregs/fregs
15224  *   -> partly done, the missing parts are:
15225  *   - a more complete unification would involve unifying the hregs as well, so
15226  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
15227  *     would no longer map to the machine hregs, so the code generators would need to
15228  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
15229  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
15230  *     fp/non-fp branches speeds it up by about 15%.
15231  * - use sext/zext opcodes instead of shifts
15232  * - add OP_ICALL
15233  * - get rid of TEMPLOADs if possible and use vregs instead
15234  * - clean up usage of OP_P/OP_ opcodes
15235  * - cleanup usage of DUMMY_USE
15236  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
15237  *   stack
15238  * - set the stack type and allocate a dreg in the EMIT_NEW macros
15239  * - get rid of all the <foo>2 stuff when the new JIT is ready.
15240  * - make sure handle_stack_args () is called before the branch is emitted
15241  * - when the new IR is done, get rid of all unused stuff
15242  * - COMPARE/BEQ as separate instructions or unify them ?
15243  *   - keeping them separate allows specialized compare instructions like
15244  *     compare_imm, compare_membase
15245  *   - most back ends unify fp compare+branch, fp compare+ceq
15246  * - integrate mono_save_args into inline_method
15247  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
15248  * - handle long shift opts on 32 bit platforms somehow: they require 
15249  *   3 sregs (2 for arg1 and 1 for arg2)
15250  * - make byref a 'normal' type.
15251  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
15252  *   variable if needed.
15253  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
15254  *   like inline_method.
15255  * - remove inlining restrictions
15256  * - fix LNEG and enable cfold of INEG
15257  * - generalize x86 optimizations like ldelema as a peephole optimization
15258  * - add store_mem_imm for amd64
15259  * - optimize the loading of the interruption flag in the managed->native wrappers
15260  * - avoid special handling of OP_NOP in passes
15261  * - move code inserting instructions into one function/macro.
15262  * - try a coalescing phase after liveness analysis
15263  * - add float -> vreg conversion + local optimizations on !x86
15264  * - figure out how to handle decomposed branches during optimizations, ie.
15265  *   compare+branch, op_jump_table+op_br etc.
15266  * - promote RuntimeXHandles to vregs
15267  * - vtype cleanups:
15268  *   - add a NEW_VARLOADA_VREG macro
15269  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
15270  *   accessing vtype fields.
15271  * - get rid of I8CONST on 64 bit platforms
15272  * - dealing with the increase in code size due to branches created during opcode
15273  *   decomposition:
15274  *   - use extended basic blocks
15275  *     - all parts of the JIT
15276  *     - handle_global_vregs () && local regalloc
15277  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
15278  * - sources of increase in code size:
15279  *   - vtypes
15280  *   - long compares
15281  *   - isinst and castclass
15282  *   - lvregs not allocated to global registers even if used multiple times
15283  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
15284  *   meaningful.
15285  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
15286  * - add all micro optimizations from the old JIT
15287  * - put tree optimizations into the deadce pass
15288  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
15289  *   specific function.
15290  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
15291  *   fcompare + branchCC.
15292  * - create a helper function for allocating a stack slot, taking into account 
15293  *   MONO_CFG_HAS_SPILLUP.
15294  * - merge r68207.
15295  * - merge the ia64 switch changes.
15296  * - optimize mono_regstate2_alloc_int/float.
15297  * - fix the pessimistic handling of variables accessed in exception handler blocks.
15298  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
15299  *   parts of the tree could be separated by other instructions, killing the tree
15300  *   arguments, or stores killing loads etc. Also, should we fold loads into other
15301  *   instructions if the result of the load is used multiple times ?
15302  * - make the REM_IMM optimization in mini-x86.c arch-independent.
15303  * - LAST MERGE: 108395.
15304  * - when returning vtypes in registers, generate IR and append it to the end of the
15305  *   last bb instead of doing it in the epilog.
15306  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
15307  */
15308
15309 /*
15310
15311 NOTES
15312 -----
15313
15314 - When to decompose opcodes:
15315   - earlier: this makes some optimizations hard to implement, since the low level IR
15316   no longer contains the neccessary information. But it is easier to do.
15317   - later: harder to implement, enables more optimizations.
15318 - Branches inside bblocks:
15319   - created when decomposing complex opcodes. 
15320     - branches to another bblock: harmless, but not tracked by the branch 
15321       optimizations, so need to branch to a label at the start of the bblock.
15322     - branches to inside the same bblock: very problematic, trips up the local
15323       reg allocator. Can be fixed by spitting the current bblock, but that is a
15324       complex operation, since some local vregs can become global vregs etc.
15325 - Local/global vregs:
15326   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
15327     local register allocator.
15328   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
15329     structure, created by mono_create_var (). Assigned to hregs or the stack by
15330     the global register allocator.
15331 - When to do optimizations like alu->alu_imm:
15332   - earlier -> saves work later on since the IR will be smaller/simpler
15333   - later -> can work on more instructions
15334 - Handling of valuetypes:
15335   - When a vtype is pushed on the stack, a new temporary is created, an 
15336     instruction computing its address (LDADDR) is emitted and pushed on
15337     the stack. Need to optimize cases when the vtype is used immediately as in
15338     argument passing, stloc etc.
15339 - Instead of the to_end stuff in the old JIT, simply call the function handling
15340   the values on the stack before emitting the last instruction of the bb.
15341 */
15342
15343 #else /* !DISABLE_JIT */
15344
15345 MONO_EMPTY_SOURCE_FILE (method_to_ir);
15346
15347 #endif /* !DISABLE_JIT */