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