Merge pull request #4063 from ntherning/fix-culture-info-problem-in-RepeatInfoTest
[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 MonoInst*
1578 mini_emit_runtime_constant (MonoCompile *cfg, MonoJumpInfoType patch_type, gpointer data)
1579 {
1580         return emit_runtime_constant (cfg, patch_type, data);
1581 }
1582
1583 static void 
1584 mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
1585 {
1586         int val_reg;
1587
1588         g_assert (val == 0);
1589
1590         if (align == 0)
1591                 align = 4;
1592
1593         if ((size <= SIZEOF_REGISTER) && (size <= align)) {
1594                 switch (size) {
1595                 case 1:
1596                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, destreg, offset, val);
1597                         return;
1598                 case 2:
1599                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI2_MEMBASE_IMM, destreg, offset, val);
1600                         return;
1601                 case 4:
1602                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, destreg, offset, val);
1603                         return;
1604 #if SIZEOF_REGISTER == 8
1605                 case 8:
1606                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI8_MEMBASE_IMM, destreg, offset, val);
1607                         return;
1608 #endif
1609                 }
1610         }
1611
1612         val_reg = alloc_preg (cfg);
1613
1614         if (SIZEOF_REGISTER == 8)
1615                 MONO_EMIT_NEW_I8CONST (cfg, val_reg, val);
1616         else
1617                 MONO_EMIT_NEW_ICONST (cfg, val_reg, val);
1618
1619         if (align < 4) {
1620                 /* This could be optimized further if neccesary */
1621                 while (size >= 1) {
1622                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1623                         offset += 1;
1624                         size -= 1;
1625                 }
1626                 return;
1627         }       
1628
1629         if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
1630                 if (offset % 8) {
1631                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1632                         offset += 4;
1633                         size -= 4;
1634                 }
1635                 while (size >= 8) {
1636                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, offset, val_reg);
1637                         offset += 8;
1638                         size -= 8;
1639                 }
1640         }       
1641
1642         while (size >= 4) {
1643                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1644                 offset += 4;
1645                 size -= 4;
1646         }
1647         while (size >= 2) {
1648                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg);
1649                 offset += 2;
1650                 size -= 2;
1651         }
1652         while (size >= 1) {
1653                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1654                 offset += 1;
1655                 size -= 1;
1656         }
1657 }
1658
1659 void 
1660 mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
1661 {
1662         int cur_reg;
1663
1664         if (align == 0)
1665                 align = 4;
1666
1667         /*FIXME arbitrary hack to avoid unbound code expansion.*/
1668         g_assert (size < 10000);
1669
1670         if (align < 4) {
1671                 /* This could be optimized further if neccesary */
1672                 while (size >= 1) {
1673                         cur_reg = alloc_preg (cfg);
1674                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1675                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1676                         doffset += 1;
1677                         soffset += 1;
1678                         size -= 1;
1679                 }
1680         }
1681
1682         if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
1683                 while (size >= 8) {
1684                         cur_reg = alloc_preg (cfg);
1685                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI8_MEMBASE, cur_reg, srcreg, soffset);
1686                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, doffset, cur_reg);
1687                         doffset += 8;
1688                         soffset += 8;
1689                         size -= 8;
1690                 }
1691         }       
1692
1693         while (size >= 4) {
1694                 cur_reg = alloc_preg (cfg);
1695                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, cur_reg, srcreg, soffset);
1696                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, doffset, cur_reg);
1697                 doffset += 4;
1698                 soffset += 4;
1699                 size -= 4;
1700         }
1701         while (size >= 2) {
1702                 cur_reg = alloc_preg (cfg);
1703                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, cur_reg, srcreg, soffset);
1704                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, doffset, cur_reg);
1705                 doffset += 2;
1706                 soffset += 2;
1707                 size -= 2;
1708         }
1709         while (size >= 1) {
1710                 cur_reg = alloc_preg (cfg);
1711                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1712                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1713                 doffset += 1;
1714                 soffset += 1;
1715                 size -= 1;
1716         }
1717 }
1718
1719 static void
1720 emit_tls_set (MonoCompile *cfg, int sreg1, MonoTlsKey tls_key)
1721 {
1722         MonoInst *ins, *c;
1723
1724         if (cfg->compile_aot) {
1725                 EMIT_NEW_TLS_OFFSETCONST (cfg, c, tls_key);
1726                 MONO_INST_NEW (cfg, ins, OP_TLS_SET_REG);
1727                 ins->sreg1 = sreg1;
1728                 ins->sreg2 = c->dreg;
1729                 MONO_ADD_INS (cfg->cbb, ins);
1730         } else {
1731                 MONO_INST_NEW (cfg, ins, OP_TLS_SET);
1732                 ins->sreg1 = sreg1;
1733                 ins->inst_offset = mini_get_tls_offset (tls_key);
1734                 MONO_ADD_INS (cfg->cbb, ins);
1735         }
1736 }
1737
1738 /*
1739  * emit_push_lmf:
1740  *
1741  *   Emit IR to push the current LMF onto the LMF stack.
1742  */
1743 static void
1744 emit_push_lmf (MonoCompile *cfg)
1745 {
1746         /*
1747          * Emit IR to push the LMF:
1748          * lmf_addr = <lmf_addr from tls>
1749          * lmf->lmf_addr = lmf_addr
1750          * lmf->prev_lmf = *lmf_addr
1751          * *lmf_addr = lmf
1752          */
1753         int lmf_reg, prev_lmf_reg;
1754         MonoInst *ins, *lmf_ins;
1755
1756         if (!cfg->lmf_ir)
1757                 return;
1758
1759         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
1760                 /* Load current lmf */
1761                 lmf_ins = mono_get_lmf_intrinsic (cfg);
1762                 g_assert (lmf_ins);
1763                 MONO_ADD_INS (cfg->cbb, lmf_ins);
1764                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
1765                 lmf_reg = ins->dreg;
1766                 /* Save previous_lmf */
1767                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), lmf_ins->dreg);
1768                 /* Set new LMF */
1769                 emit_tls_set (cfg, lmf_reg, TLS_KEY_LMF);
1770         } else {
1771                 /*
1772                  * Store lmf_addr in a variable, so it can be allocated to a global register.
1773                  */
1774                 if (!cfg->lmf_addr_var)
1775                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1776
1777 #ifdef HOST_WIN32
1778                 ins = mono_get_jit_tls_intrinsic (cfg);
1779                 if (ins) {
1780                         int jit_tls_dreg = ins->dreg;
1781
1782                         MONO_ADD_INS (cfg->cbb, ins);
1783                         lmf_reg = alloc_preg (cfg);
1784                         EMIT_NEW_BIALU_IMM (cfg, lmf_ins, OP_PADD_IMM, lmf_reg, jit_tls_dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
1785                 } else {
1786                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
1787                 }
1788 #else
1789                 lmf_ins = mono_get_lmf_addr_intrinsic (cfg);
1790                 if (lmf_ins) {
1791                         MONO_ADD_INS (cfg->cbb, lmf_ins);
1792                 } else {
1793 #ifdef TARGET_IOS
1794                         MonoInst *args [16], *jit_tls_ins, *ins;
1795
1796                         /* Inline mono_get_lmf_addr () */
1797                         /* jit_tls = pthread_getspecific (mono_jit_tls_id); lmf_addr = &jit_tls->lmf; */
1798
1799                         /* Load mono_jit_tls_id */
1800                         if (cfg->compile_aot)
1801                                 EMIT_NEW_AOTCONST (cfg, args [0], MONO_PATCH_INFO_JIT_TLS_ID, NULL);
1802                         else
1803                                 EMIT_NEW_ICONST (cfg, args [0], mono_jit_tls_id);
1804                         /* call pthread_getspecific () */
1805                         jit_tls_ins = mono_emit_jit_icall (cfg, pthread_getspecific, args);
1806                         /* lmf_addr = &jit_tls->lmf */
1807                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, cfg->lmf_addr_var->dreg, jit_tls_ins->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
1808                         lmf_ins = ins;
1809 #else
1810                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
1811 #endif
1812                 }
1813 #endif
1814                 lmf_ins->dreg = cfg->lmf_addr_var->dreg;
1815
1816                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
1817                 lmf_reg = ins->dreg;
1818
1819                 prev_lmf_reg = alloc_preg (cfg);
1820                 /* Save previous_lmf */
1821                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, cfg->lmf_addr_var->dreg, 0);
1822                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), prev_lmf_reg);
1823                 /* Set new lmf */
1824                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, cfg->lmf_addr_var->dreg, 0, lmf_reg);
1825         }
1826 }
1827
1828 /*
1829  * emit_pop_lmf:
1830  *
1831  *   Emit IR to pop the current LMF from the LMF stack.
1832  */
1833 static void
1834 emit_pop_lmf (MonoCompile *cfg)
1835 {
1836         int lmf_reg, lmf_addr_reg, prev_lmf_reg;
1837         MonoInst *ins;
1838
1839         if (!cfg->lmf_ir)
1840                 return;
1841
1842         EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
1843         lmf_reg = ins->dreg;
1844
1845         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
1846                 /* Load previous_lmf */
1847                 prev_lmf_reg = alloc_preg (cfg);
1848                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
1849                 /* Set new LMF */
1850                 emit_tls_set (cfg, prev_lmf_reg, TLS_KEY_LMF);
1851         } else {
1852                 /*
1853                  * Emit IR to pop the LMF:
1854                  * *(lmf->lmf_addr) = lmf->prev_lmf
1855                  */
1856                 /* This could be called before emit_push_lmf () */
1857                 if (!cfg->lmf_addr_var)
1858                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1859                 lmf_addr_reg = cfg->lmf_addr_var->dreg;
1860
1861                 prev_lmf_reg = alloc_preg (cfg);
1862                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
1863                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, prev_lmf_reg);
1864         }
1865 }
1866
1867 static void
1868 emit_instrumentation_call (MonoCompile *cfg, void *func)
1869 {
1870         MonoInst *iargs [1];
1871
1872         /*
1873          * Avoid instrumenting inlined methods since it can
1874          * distort profiling results.
1875          */
1876         if (cfg->method != cfg->current_method)
1877                 return;
1878
1879         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
1880                 EMIT_NEW_METHODCONST (cfg, iargs [0], cfg->method);
1881                 mono_emit_jit_icall (cfg, func, iargs);
1882         }
1883 }
1884
1885 static int
1886 ret_type_to_call_opcode (MonoCompile *cfg, MonoType *type, int calli, int virt)
1887 {
1888 handle_enum:
1889         type = mini_get_underlying_type (type);
1890         switch (type->type) {
1891         case MONO_TYPE_VOID:
1892                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALL_MEMBASE: OP_VOIDCALL;
1893         case MONO_TYPE_I1:
1894         case MONO_TYPE_U1:
1895         case MONO_TYPE_I2:
1896         case MONO_TYPE_U2:
1897         case MONO_TYPE_I4:
1898         case MONO_TYPE_U4:
1899                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
1900         case MONO_TYPE_I:
1901         case MONO_TYPE_U:
1902         case MONO_TYPE_PTR:
1903         case MONO_TYPE_FNPTR:
1904                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
1905         case MONO_TYPE_CLASS:
1906         case MONO_TYPE_STRING:
1907         case MONO_TYPE_OBJECT:
1908         case MONO_TYPE_SZARRAY:
1909         case MONO_TYPE_ARRAY:    
1910                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
1911         case MONO_TYPE_I8:
1912         case MONO_TYPE_U8:
1913                 return calli? OP_LCALL_REG: virt? OP_LCALL_MEMBASE: OP_LCALL;
1914         case MONO_TYPE_R4:
1915                 if (cfg->r4fp)
1916                         return calli? OP_RCALL_REG: virt? OP_RCALL_MEMBASE: OP_RCALL;
1917                 else
1918                         return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
1919         case MONO_TYPE_R8:
1920                 return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
1921         case MONO_TYPE_VALUETYPE:
1922                 if (type->data.klass->enumtype) {
1923                         type = mono_class_enum_basetype (type->data.klass);
1924                         goto handle_enum;
1925                 } else
1926                         return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
1927         case MONO_TYPE_TYPEDBYREF:
1928                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
1929         case MONO_TYPE_GENERICINST:
1930                 type = &type->data.generic_class->container_class->byval_arg;
1931                 goto handle_enum;
1932         case MONO_TYPE_VAR:
1933         case MONO_TYPE_MVAR:
1934                 /* gsharedvt */
1935                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
1936         default:
1937                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
1938         }
1939         return -1;
1940 }
1941
1942 //XXX this ignores if t is byref
1943 #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)))))
1944
1945 /*
1946  * target_type_is_incompatible:
1947  * @cfg: MonoCompile context
1948  *
1949  * Check that the item @arg on the evaluation stack can be stored
1950  * in the target type (can be a local, or field, etc).
1951  * The cfg arg can be used to check if we need verification or just
1952  * validity checks.
1953  *
1954  * Returns: non-0 value if arg can't be stored on a target.
1955  */
1956 static int
1957 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
1958 {
1959         MonoType *simple_type;
1960         MonoClass *klass;
1961
1962         if (target->byref) {
1963                 /* FIXME: check that the pointed to types match */
1964                 if (arg->type == STACK_MP) {
1965                         /* This is needed to handle gshared types + ldaddr. We lower the types so we can handle enums and other typedef-like types. */
1966                         MonoClass *target_class_lowered = mono_class_from_mono_type (mini_get_underlying_type (&mono_class_from_mono_type (target)->byval_arg));
1967                         MonoClass *source_class_lowered = mono_class_from_mono_type (mini_get_underlying_type (&arg->klass->byval_arg));
1968
1969                         /* if the target is native int& or same type */
1970                         if (target->type == MONO_TYPE_I || target_class_lowered == source_class_lowered)
1971                                 return 0;
1972
1973                         /* Both are primitive type byrefs and the source points to a larger type that the destination */
1974                         if (MONO_TYPE_IS_PRIMITIVE_SCALAR (&target_class_lowered->byval_arg) && MONO_TYPE_IS_PRIMITIVE_SCALAR (&source_class_lowered->byval_arg) &&
1975                                 mono_class_instance_size (target_class_lowered) <= mono_class_instance_size (source_class_lowered))
1976                                 return 0;
1977                         return 1;
1978                 }
1979                 if (arg->type == STACK_PTR)
1980                         return 0;
1981                 return 1;
1982         }
1983
1984         simple_type = mini_get_underlying_type (target);
1985         switch (simple_type->type) {
1986         case MONO_TYPE_VOID:
1987                 return 1;
1988         case MONO_TYPE_I1:
1989         case MONO_TYPE_U1:
1990         case MONO_TYPE_I2:
1991         case MONO_TYPE_U2:
1992         case MONO_TYPE_I4:
1993         case MONO_TYPE_U4:
1994                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
1995                         return 1;
1996                 return 0;
1997         case MONO_TYPE_PTR:
1998                 /* STACK_MP is needed when setting pinned locals */
1999                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2000                         return 1;
2001                 return 0;
2002         case MONO_TYPE_I:
2003         case MONO_TYPE_U:
2004         case MONO_TYPE_FNPTR:
2005                 /* 
2006                  * Some opcodes like ldloca returns 'transient pointers' which can be stored in
2007                  * in native int. (#688008).
2008                  */
2009                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2010                         return 1;
2011                 return 0;
2012         case MONO_TYPE_CLASS:
2013         case MONO_TYPE_STRING:
2014         case MONO_TYPE_OBJECT:
2015         case MONO_TYPE_SZARRAY:
2016         case MONO_TYPE_ARRAY:    
2017                 if (arg->type != STACK_OBJ)
2018                         return 1;
2019                 /* FIXME: check type compatibility */
2020                 return 0;
2021         case MONO_TYPE_I8:
2022         case MONO_TYPE_U8:
2023                 if (arg->type != STACK_I8)
2024                         return 1;
2025                 return 0;
2026         case MONO_TYPE_R4:
2027                 if (arg->type != cfg->r4_stack_type)
2028                         return 1;
2029                 return 0;
2030         case MONO_TYPE_R8:
2031                 if (arg->type != STACK_R8)
2032                         return 1;
2033                 return 0;
2034         case MONO_TYPE_VALUETYPE:
2035                 if (arg->type != STACK_VTYPE)
2036                         return 1;
2037                 klass = mono_class_from_mono_type (simple_type);
2038                 if (klass != arg->klass)
2039                         return 1;
2040                 return 0;
2041         case MONO_TYPE_TYPEDBYREF:
2042                 if (arg->type != STACK_VTYPE)
2043                         return 1;
2044                 klass = mono_class_from_mono_type (simple_type);
2045                 if (klass != arg->klass)
2046                         return 1;
2047                 return 0;
2048         case MONO_TYPE_GENERICINST:
2049                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2050                         MonoClass *target_class;
2051                         if (arg->type != STACK_VTYPE)
2052                                 return 1;
2053                         klass = mono_class_from_mono_type (simple_type);
2054                         target_class = mono_class_from_mono_type (target);
2055                         /* The second cases is needed when doing partial sharing */
2056                         if (klass != arg->klass && target_class != arg->klass && target_class != mono_class_from_mono_type (mini_get_underlying_type (&arg->klass->byval_arg)))
2057                                 return 1;
2058                         return 0;
2059                 } else {
2060                         if (arg->type != STACK_OBJ)
2061                                 return 1;
2062                         /* FIXME: check type compatibility */
2063                         return 0;
2064                 }
2065         case MONO_TYPE_VAR:
2066         case MONO_TYPE_MVAR:
2067                 g_assert (cfg->gshared);
2068                 if (mini_type_var_is_vt (simple_type)) {
2069                         if (arg->type != STACK_VTYPE)
2070                                 return 1;
2071                 } else {
2072                         if (arg->type != STACK_OBJ)
2073                                 return 1;
2074                 }
2075                 return 0;
2076         default:
2077                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2078         }
2079         return 1;
2080 }
2081
2082 /*
2083  * Prepare arguments for passing to a function call.
2084  * Return a non-zero value if the arguments can't be passed to the given
2085  * signature.
2086  * The type checks are not yet complete and some conversions may need
2087  * casts on 32 or 64 bit architectures.
2088  *
2089  * FIXME: implement this using target_type_is_incompatible ()
2090  */
2091 static int
2092 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2093 {
2094         MonoType *simple_type;
2095         int i;
2096
2097         if (sig->hasthis) {
2098                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2099                         return 1;
2100                 args++;
2101         }
2102         for (i = 0; i < sig->param_count; ++i) {
2103                 if (sig->params [i]->byref) {
2104                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2105                                 return 1;
2106                         continue;
2107                 }
2108                 simple_type = mini_get_underlying_type (sig->params [i]);
2109 handle_enum:
2110                 switch (simple_type->type) {
2111                 case MONO_TYPE_VOID:
2112                         return 1;
2113                         continue;
2114                 case MONO_TYPE_I1:
2115                 case MONO_TYPE_U1:
2116                 case MONO_TYPE_I2:
2117                 case MONO_TYPE_U2:
2118                 case MONO_TYPE_I4:
2119                 case MONO_TYPE_U4:
2120                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2121                                 return 1;
2122                         continue;
2123                 case MONO_TYPE_I:
2124                 case MONO_TYPE_U:
2125                 case MONO_TYPE_PTR:
2126                 case MONO_TYPE_FNPTR:
2127                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2128                                 return 1;
2129                         continue;
2130                 case MONO_TYPE_CLASS:
2131                 case MONO_TYPE_STRING:
2132                 case MONO_TYPE_OBJECT:
2133                 case MONO_TYPE_SZARRAY:
2134                 case MONO_TYPE_ARRAY:    
2135                         if (args [i]->type != STACK_OBJ)
2136                                 return 1;
2137                         continue;
2138                 case MONO_TYPE_I8:
2139                 case MONO_TYPE_U8:
2140                         if (args [i]->type != STACK_I8)
2141                                 return 1;
2142                         continue;
2143                 case MONO_TYPE_R4:
2144                         if (args [i]->type != cfg->r4_stack_type)
2145                                 return 1;
2146                         continue;
2147                 case MONO_TYPE_R8:
2148                         if (args [i]->type != STACK_R8)
2149                                 return 1;
2150                         continue;
2151                 case MONO_TYPE_VALUETYPE:
2152                         if (simple_type->data.klass->enumtype) {
2153                                 simple_type = mono_class_enum_basetype (simple_type->data.klass);
2154                                 goto handle_enum;
2155                         }
2156                         if (args [i]->type != STACK_VTYPE)
2157                                 return 1;
2158                         continue;
2159                 case MONO_TYPE_TYPEDBYREF:
2160                         if (args [i]->type != STACK_VTYPE)
2161                                 return 1;
2162                         continue;
2163                 case MONO_TYPE_GENERICINST:
2164                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2165                         goto handle_enum;
2166                 case MONO_TYPE_VAR:
2167                 case MONO_TYPE_MVAR:
2168                         /* gsharedvt */
2169                         if (args [i]->type != STACK_VTYPE)
2170                                 return 1;
2171                         continue;
2172                 default:
2173                         g_error ("unknown type 0x%02x in check_call_signature",
2174                                  simple_type->type);
2175                 }
2176         }
2177         return 0;
2178 }
2179
2180 static int
2181 callvirt_to_call (int opcode)
2182 {
2183         switch (opcode) {
2184         case OP_CALL_MEMBASE:
2185                 return OP_CALL;
2186         case OP_VOIDCALL_MEMBASE:
2187                 return OP_VOIDCALL;
2188         case OP_FCALL_MEMBASE:
2189                 return OP_FCALL;
2190         case OP_RCALL_MEMBASE:
2191                 return OP_RCALL;
2192         case OP_VCALL_MEMBASE:
2193                 return OP_VCALL;
2194         case OP_LCALL_MEMBASE:
2195                 return OP_LCALL;
2196         default:
2197                 g_assert_not_reached ();
2198         }
2199
2200         return -1;
2201 }
2202
2203 static int
2204 callvirt_to_call_reg (int opcode)
2205 {
2206         switch (opcode) {
2207         case OP_CALL_MEMBASE:
2208                 return OP_CALL_REG;
2209         case OP_VOIDCALL_MEMBASE:
2210                 return OP_VOIDCALL_REG;
2211         case OP_FCALL_MEMBASE:
2212                 return OP_FCALL_REG;
2213         case OP_RCALL_MEMBASE:
2214                 return OP_RCALL_REG;
2215         case OP_VCALL_MEMBASE:
2216                 return OP_VCALL_REG;
2217         case OP_LCALL_MEMBASE:
2218                 return OP_LCALL_REG;
2219         default:
2220                 g_assert_not_reached ();
2221         }
2222
2223         return -1;
2224 }
2225
2226 /* Either METHOD or IMT_ARG needs to be set */
2227 static void
2228 emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoMethod *method, MonoInst *imt_arg)
2229 {
2230         int method_reg;
2231
2232         if (COMPILE_LLVM (cfg)) {
2233                 if (imt_arg) {
2234                         method_reg = alloc_preg (cfg);
2235                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2236                 } else {
2237                         MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
2238                         method_reg = ins->dreg;
2239                 }
2240
2241 #ifdef ENABLE_LLVM
2242                 call->imt_arg_reg = method_reg;
2243 #endif
2244                 mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2245                 return;
2246         }
2247
2248         if (imt_arg) {
2249                 method_reg = alloc_preg (cfg);
2250                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2251         } else {
2252                 MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
2253                 method_reg = ins->dreg;
2254         }
2255
2256         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2257 }
2258
2259 static MonoJumpInfo *
2260 mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpointer target)
2261 {
2262         MonoJumpInfo *ji = (MonoJumpInfo *)mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
2263
2264         ji->ip.i = ip;
2265         ji->type = type;
2266         ji->data.target = target;
2267
2268         return ji;
2269 }
2270
2271 static int
2272 mini_class_check_context_used (MonoCompile *cfg, MonoClass *klass)
2273 {
2274         if (cfg->gshared)
2275                 return mono_class_check_context_used (klass);
2276         else
2277                 return 0;
2278 }
2279
2280 static int
2281 mini_method_check_context_used (MonoCompile *cfg, MonoMethod *method)
2282 {
2283         if (cfg->gshared)
2284                 return mono_method_check_context_used (method);
2285         else
2286                 return 0;
2287 }
2288
2289 /*
2290  * check_method_sharing:
2291  *
2292  *   Check whenever the vtable or an mrgctx needs to be passed when calling CMETHOD.
2293  */
2294 static void
2295 check_method_sharing (MonoCompile *cfg, MonoMethod *cmethod, gboolean *out_pass_vtable, gboolean *out_pass_mrgctx)
2296 {
2297         gboolean pass_vtable = FALSE;
2298         gboolean pass_mrgctx = FALSE;
2299
2300         if (((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
2301                 (mono_class_is_ginst (cmethod->klass) || mono_class_is_gtd (cmethod->klass))) {
2302                 gboolean sharable = FALSE;
2303
2304                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE))
2305                         sharable = TRUE;
2306
2307                 /*
2308                  * Pass vtable iff target method might
2309                  * be shared, which means that sharing
2310                  * is enabled for its class and its
2311                  * context is sharable (and it's not a
2312                  * generic method).
2313                  */
2314                 if (sharable && !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
2315                         pass_vtable = TRUE;
2316         }
2317
2318         if (mini_method_get_context (cmethod) &&
2319                 mini_method_get_context (cmethod)->method_inst) {
2320                 g_assert (!pass_vtable);
2321
2322                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE)) {
2323                         pass_mrgctx = TRUE;
2324                 } else {
2325                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (mono_method_signature (cmethod)))
2326                                 pass_mrgctx = TRUE;
2327                 }
2328         }
2329
2330         if (out_pass_vtable)
2331                 *out_pass_vtable = pass_vtable;
2332         if (out_pass_mrgctx)
2333                 *out_pass_mrgctx = pass_mrgctx;
2334 }
2335
2336 inline static MonoCallInst *
2337 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
2338                                          MonoInst **args, int calli, int virtual_, int tail, int rgctx, int unbox_trampoline)
2339 {
2340         MonoType *sig_ret;
2341         MonoCallInst *call;
2342 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2343         int i;
2344 #endif
2345
2346         if (cfg->llvm_only)
2347                 tail = FALSE;
2348
2349         if (tail) {
2350                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
2351
2352                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
2353         } else
2354                 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (cfg, sig->ret, calli, virtual_));
2355
2356         call->args = args;
2357         call->signature = sig;
2358         call->rgctx_reg = rgctx;
2359         sig_ret = mini_get_underlying_type (sig->ret);
2360
2361         type_to_eval_stack_type ((cfg), sig_ret, &call->inst);
2362
2363         if (tail) {
2364                 if (mini_type_is_vtype (sig_ret)) {
2365                         call->vret_var = cfg->vret_addr;
2366                         //g_assert_not_reached ();
2367                 }
2368         } else if (mini_type_is_vtype (sig_ret)) {
2369                 MonoInst *temp = mono_compile_create_var (cfg, sig_ret, OP_LOCAL);
2370                 MonoInst *loada;
2371
2372                 temp->backend.is_pinvoke = sig->pinvoke;
2373
2374                 /*
2375                  * We use a new opcode OP_OUTARG_VTRETADDR instead of LDADDR for emitting the
2376                  * address of return value to increase optimization opportunities.
2377                  * Before vtype decomposition, the dreg of the call ins itself represents the
2378                  * fact the call modifies the return value. After decomposition, the call will
2379                  * be transformed into one of the OP_VOIDCALL opcodes, and the VTRETADDR opcode
2380                  * will be transformed into an LDADDR.
2381                  */
2382                 MONO_INST_NEW (cfg, loada, OP_OUTARG_VTRETADDR);
2383                 loada->dreg = alloc_preg (cfg);
2384                 loada->inst_p0 = temp;
2385                 /* We reference the call too since call->dreg could change during optimization */
2386                 loada->inst_p1 = call;
2387                 MONO_ADD_INS (cfg->cbb, loada);
2388
2389                 call->inst.dreg = temp->dreg;
2390
2391                 call->vret_var = loada;
2392         } else if (!MONO_TYPE_IS_VOID (sig_ret))
2393                 call->inst.dreg = alloc_dreg (cfg, (MonoStackType)call->inst.type);
2394
2395 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2396         if (COMPILE_SOFT_FLOAT (cfg)) {
2397                 /* 
2398                  * If the call has a float argument, we would need to do an r8->r4 conversion using 
2399                  * an icall, but that cannot be done during the call sequence since it would clobber
2400                  * the call registers + the stack. So we do it before emitting the call.
2401                  */
2402                 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2403                         MonoType *t;
2404                         MonoInst *in = call->args [i];
2405
2406                         if (i >= sig->hasthis)
2407                                 t = sig->params [i - sig->hasthis];
2408                         else
2409                                 t = &mono_defaults.int_class->byval_arg;
2410                         t = mono_type_get_underlying_type (t);
2411
2412                         if (!t->byref && t->type == MONO_TYPE_R4) {
2413                                 MonoInst *iargs [1];
2414                                 MonoInst *conv;
2415
2416                                 iargs [0] = in;
2417                                 conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
2418
2419                                 /* The result will be in an int vreg */
2420                                 call->args [i] = conv;
2421                         }
2422                 }
2423         }
2424 #endif
2425
2426         call->need_unbox_trampoline = unbox_trampoline;
2427
2428 #ifdef ENABLE_LLVM
2429         if (COMPILE_LLVM (cfg))
2430                 mono_llvm_emit_call (cfg, call);
2431         else
2432                 mono_arch_emit_call (cfg, call);
2433 #else
2434         mono_arch_emit_call (cfg, call);
2435 #endif
2436
2437         cfg->param_area = MAX (cfg->param_area, call->stack_usage);
2438         cfg->flags |= MONO_CFG_HAS_CALLS;
2439         
2440         return call;
2441 }
2442
2443 static void
2444 set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rgctx_arg)
2445 {
2446         mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
2447         cfg->uses_rgctx_reg = TRUE;
2448         call->rgctx_reg = TRUE;
2449 #ifdef ENABLE_LLVM
2450         call->rgctx_arg_reg = rgctx_reg;
2451 #endif
2452 }       
2453
2454 inline static MonoInst*
2455 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg)
2456 {
2457         MonoCallInst *call;
2458         MonoInst *ins;
2459         int rgctx_reg = -1;
2460         gboolean check_sp = FALSE;
2461
2462         if (cfg->check_pinvoke_callconv && cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
2463                 WrapperInfo *info = mono_marshal_get_wrapper_info (cfg->method);
2464
2465                 if (info && info->subtype == WRAPPER_SUBTYPE_PINVOKE)
2466                         check_sp = TRUE;
2467         }
2468
2469         if (rgctx_arg) {
2470                 rgctx_reg = mono_alloc_preg (cfg);
2471                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2472         }
2473
2474         if (check_sp) {
2475                 if (!cfg->stack_inbalance_var)
2476                         cfg->stack_inbalance_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2477
2478                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2479                 ins->dreg = cfg->stack_inbalance_var->dreg;
2480                 MONO_ADD_INS (cfg->cbb, ins);
2481         }
2482
2483         call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE);
2484
2485         call->inst.sreg1 = addr->dreg;
2486
2487         if (imt_arg)
2488                 emit_imt_argument (cfg, call, NULL, imt_arg);
2489
2490         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2491
2492         if (check_sp) {
2493                 int sp_reg;
2494
2495                 sp_reg = mono_alloc_preg (cfg);
2496
2497                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2498                 ins->dreg = sp_reg;
2499                 MONO_ADD_INS (cfg->cbb, ins);
2500
2501                 /* Restore the stack so we don't crash when throwing the exception */
2502                 MONO_INST_NEW (cfg, ins, OP_SET_SP);
2503                 ins->sreg1 = cfg->stack_inbalance_var->dreg;
2504                 MONO_ADD_INS (cfg->cbb, ins);
2505
2506                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, cfg->stack_inbalance_var->dreg, sp_reg);
2507                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ExecutionEngineException");
2508         }
2509
2510         if (rgctx_arg)
2511                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2512
2513         return (MonoInst*)call;
2514 }
2515
2516 static MonoInst*
2517 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2518
2519 static MonoInst*
2520 emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type);
2521
2522 static MonoInst*
2523 mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig, gboolean tail,
2524                                                         MonoInst **args, MonoInst *this_ins, MonoInst *imt_arg, MonoInst *rgctx_arg)
2525 {
2526 #ifndef DISABLE_REMOTING
2527         gboolean might_be_remote = FALSE;
2528 #endif
2529         gboolean virtual_ = this_ins != NULL;
2530         gboolean enable_for_aot = TRUE;
2531         int context_used;
2532         MonoCallInst *call;
2533         MonoInst *call_target = NULL;
2534         int rgctx_reg = 0;
2535         gboolean need_unbox_trampoline;
2536
2537         if (!sig)
2538                 sig = mono_method_signature (method);
2539
2540         if (cfg->llvm_only && (mono_class_is_interface (method->klass)))
2541                 g_assert_not_reached ();
2542
2543         if (rgctx_arg) {
2544                 rgctx_reg = mono_alloc_preg (cfg);
2545                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2546         }
2547
2548         if (method->string_ctor) {
2549                 /* Create the real signature */
2550                 /* FIXME: Cache these */
2551                 MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_mempool (cfg->mempool, sig);
2552                 ctor_sig->ret = &mono_defaults.string_class->byval_arg;
2553
2554                 sig = ctor_sig;
2555         }
2556
2557         context_used = mini_method_check_context_used (cfg, method);
2558
2559 #ifndef DISABLE_REMOTING
2560         might_be_remote = this_ins && sig->hasthis &&
2561                 (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) &&
2562                 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && (!MONO_CHECK_THIS (this_ins) || context_used);
2563
2564         if (might_be_remote && context_used) {
2565                 MonoInst *addr;
2566
2567                 g_assert (cfg->gshared);
2568
2569                 addr = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK);
2570
2571                 return mono_emit_calli (cfg, sig, args, addr, NULL, NULL);
2572         }
2573 #endif
2574
2575         if (cfg->llvm_only && !call_target && virtual_ && (method->flags & METHOD_ATTRIBUTE_VIRTUAL))
2576                 return emit_llvmonly_virtual_call (cfg, method, sig, 0, args);
2577
2578         need_unbox_trampoline = method->klass == mono_defaults.object_class || mono_class_is_interface (method->klass);
2579
2580         call = mono_emit_call_args (cfg, sig, args, FALSE, virtual_, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline);
2581
2582 #ifndef DISABLE_REMOTING
2583         if (might_be_remote)
2584                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2585         else
2586 #endif
2587                 call->method = method;
2588         call->inst.flags |= MONO_INST_HAS_METHOD;
2589         call->inst.inst_left = this_ins;
2590         call->tail_call = tail;
2591
2592         if (virtual_) {
2593                 int vtable_reg, slot_reg, this_reg;
2594                 int offset;
2595
2596                 this_reg = this_ins->dreg;
2597
2598                 if (!cfg->llvm_only && (method->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (method->name, "Invoke")) {
2599                         MonoInst *dummy_use;
2600
2601                         MONO_EMIT_NULL_CHECK (cfg, this_reg);
2602
2603                         /* Make a call to delegate->invoke_impl */
2604                         call->inst.inst_basereg = this_reg;
2605                         call->inst.inst_offset = MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl);
2606                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2607
2608                         /* We must emit a dummy use here because the delegate trampoline will
2609                         replace the 'this' argument with the delegate target making this activation
2610                         no longer a root for the delegate.
2611                         This is an issue for delegates that target collectible code such as dynamic
2612                         methods of GC'able assemblies.
2613
2614                         For a test case look into #667921.
2615
2616                         FIXME: a dummy use is not the best way to do it as the local register allocator
2617                         will put it on a caller save register and spil it around the call. 
2618                         Ideally, we would either put it on a callee save register or only do the store part.  
2619                          */
2620                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [0]);
2621
2622                         return (MonoInst*)call;
2623                 }
2624
2625                 if ((!cfg->compile_aot || enable_for_aot) && 
2626                         (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
2627                          (MONO_METHOD_IS_FINAL (method) &&
2628                           method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)) &&
2629                         !(mono_class_is_marshalbyref (method->klass) && context_used)) {
2630                         /* 
2631                          * the method is not virtual, we just need to ensure this is not null
2632                          * and then we can call the method directly.
2633                          */
2634 #ifndef DISABLE_REMOTING
2635                         if (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) {
2636                                 /* 
2637                                  * The check above ensures method is not gshared, this is needed since
2638                                  * gshared methods can't have wrappers.
2639                                  */
2640                                 method = call->method = mono_marshal_get_remoting_invoke_with_check (method);
2641                         }
2642 #endif
2643
2644                         if (!method->string_ctor)
2645                                 MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2646
2647                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2648                 } else if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && MONO_METHOD_IS_FINAL (method)) {
2649                         /*
2650                          * the method is virtual, but we can statically dispatch since either
2651                          * it's class or the method itself are sealed.
2652                          * But first we need to ensure it's not a null reference.
2653                          */
2654                         MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2655
2656                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2657                 } else if (call_target) {
2658                         vtable_reg = alloc_preg (cfg);
2659                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2660
2661                         call->inst.opcode = callvirt_to_call_reg (call->inst.opcode);
2662                         call->inst.sreg1 = call_target->dreg;
2663                         call->inst.flags &= !MONO_INST_HAS_METHOD;
2664                 } else {
2665                         vtable_reg = alloc_preg (cfg);
2666                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2667                         if (mono_class_is_interface (method->klass)) {
2668                                 guint32 imt_slot = mono_method_get_imt_slot (method);
2669                                 emit_imt_argument (cfg, call, call->method, imt_arg);
2670                                 slot_reg = vtable_reg;
2671                                 offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
2672                         } else {
2673                                 slot_reg = vtable_reg;
2674                                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) +
2675                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
2676                                 if (imt_arg) {
2677                                         g_assert (mono_method_signature (method)->generic_param_count);
2678                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2679                                 }
2680                         }
2681
2682                         call->inst.sreg1 = slot_reg;
2683                         call->inst.inst_offset = offset;
2684                         call->is_virtual = TRUE;
2685                 }
2686         }
2687
2688         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2689
2690         if (rgctx_arg)
2691                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2692
2693         return (MonoInst*)call;
2694 }
2695
2696 MonoInst*
2697 mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this_ins)
2698 {
2699         return mono_emit_method_call_full (cfg, method, mono_method_signature (method), FALSE, args, this_ins, NULL, NULL);
2700 }
2701
2702 MonoInst*
2703 mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig,
2704                                            MonoInst **args)
2705 {
2706         MonoCallInst *call;
2707
2708         g_assert (sig);
2709
2710         call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE, FALSE, FALSE);
2711         call->fptr = func;
2712
2713         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2714
2715         return (MonoInst*)call;
2716 }
2717
2718 MonoInst*
2719 mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args)
2720 {
2721         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2722
2723         g_assert (info);
2724
2725         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2726 }
2727
2728 /*
2729  * mono_emit_abs_call:
2730  *
2731  *   Emit a call to the runtime function described by PATCH_TYPE and DATA.
2732  */
2733 inline static MonoInst*
2734 mono_emit_abs_call (MonoCompile *cfg, MonoJumpInfoType patch_type, gconstpointer data, 
2735                                         MonoMethodSignature *sig, MonoInst **args)
2736 {
2737         MonoJumpInfo *ji = mono_patch_info_new (cfg->mempool, 0, patch_type, data);
2738         MonoInst *ins;
2739
2740         /* 
2741          * We pass ji as the call address, the PATCH_INFO_ABS resolving code will
2742          * handle it.
2743          */
2744         if (cfg->abs_patches == NULL)
2745                 cfg->abs_patches = g_hash_table_new (NULL, NULL);
2746         g_hash_table_insert (cfg->abs_patches, ji, ji);
2747         ins = mono_emit_native_call (cfg, ji, sig, args);
2748         ((MonoCallInst*)ins)->fptr_is_patch = TRUE;
2749         return ins;
2750 }
2751
2752 static MonoMethodSignature*
2753 sig_to_rgctx_sig (MonoMethodSignature *sig)
2754 {
2755         // FIXME: memory allocation
2756         MonoMethodSignature *res;
2757         int i;
2758
2759         res = (MonoMethodSignature *)g_malloc (MONO_SIZEOF_METHOD_SIGNATURE + (sig->param_count + 1) * sizeof (MonoType*));
2760         memcpy (res, sig, MONO_SIZEOF_METHOD_SIGNATURE);
2761         res->param_count = sig->param_count + 1;
2762         for (i = 0; i < sig->param_count; ++i)
2763                 res->params [i] = sig->params [i];
2764         res->params [sig->param_count] = &mono_defaults.int_class->this_arg;
2765         return res;
2766 }
2767
2768 /* Make an indirect call to FSIG passing an additional argument */
2769 static MonoInst*
2770 emit_extra_arg_calli (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **orig_args, int arg_reg, MonoInst *call_target)
2771 {
2772         MonoMethodSignature *csig;
2773         MonoInst *args_buf [16];
2774         MonoInst **args;
2775         int i, pindex, tmp_reg;
2776
2777         /* Make a call with an rgctx/extra arg */
2778         if (fsig->param_count + 2 < 16)
2779                 args = args_buf;
2780         else
2781                 args = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (fsig->param_count + 2));
2782         pindex = 0;
2783         if (fsig->hasthis)
2784                 args [pindex ++] = orig_args [0];
2785         for (i = 0; i < fsig->param_count; ++i)
2786                 args [pindex ++] = orig_args [fsig->hasthis + i];
2787         tmp_reg = alloc_preg (cfg);
2788         EMIT_NEW_UNALU (cfg, args [pindex], OP_MOVE, tmp_reg, arg_reg);
2789         csig = sig_to_rgctx_sig (fsig);
2790         return mono_emit_calli (cfg, csig, args, call_target, NULL, NULL);
2791 }
2792
2793 /* Emit an indirect call to the function descriptor ADDR */
2794 static MonoInst*
2795 emit_llvmonly_calli (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, MonoInst *addr)
2796 {
2797         int addr_reg, arg_reg;
2798         MonoInst *call_target;
2799
2800         g_assert (cfg->llvm_only);
2801
2802         /*
2803          * addr points to a <addr, arg> pair, load both of them, and
2804          * make a call to addr, passing arg as an extra arg.
2805          */
2806         addr_reg = alloc_preg (cfg);
2807         EMIT_NEW_LOAD_MEMBASE (cfg, call_target, OP_LOAD_MEMBASE, addr_reg, addr->dreg, 0);
2808         arg_reg = alloc_preg (cfg);
2809         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, arg_reg, addr->dreg, sizeof (gpointer));
2810
2811         return emit_extra_arg_calli (cfg, fsig, args, arg_reg, call_target);
2812 }
2813
2814 static gboolean
2815 direct_icalls_enabled (MonoCompile *cfg)
2816 {
2817         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
2818 #ifdef TARGET_AMD64
2819         if (cfg->compile_llvm && !cfg->llvm_only)
2820                 return FALSE;
2821 #endif
2822         if (cfg->gen_sdb_seq_points || cfg->disable_direct_icalls)
2823                 return FALSE;
2824         return TRUE;
2825 }
2826
2827 MonoInst*
2828 mono_emit_jit_icall_by_info (MonoCompile *cfg, int il_offset, MonoJitICallInfo *info, MonoInst **args)
2829 {
2830         /*
2831          * Call the jit icall without a wrapper if possible.
2832          * The wrapper is needed for the following reasons:
2833          * - to handle exceptions thrown using mono_raise_exceptions () from the
2834          *   icall function. The EH code needs the lmf frame pushed by the
2835          *   wrapper to be able to unwind back to managed code.
2836          * - to be able to do stack walks for asynchronously suspended
2837          *   threads when debugging.
2838          */
2839         if (info->no_raise && direct_icalls_enabled (cfg)) {
2840                 char *name;
2841                 int costs;
2842
2843                 if (!info->wrapper_method) {
2844                         name = g_strdup_printf ("__icall_wrapper_%s", info->name);
2845                         info->wrapper_method = mono_marshal_get_icall_wrapper (info->sig, name, info->func, TRUE);
2846                         g_free (name);
2847                         mono_memory_barrier ();
2848                 }
2849
2850                 /*
2851                  * Inline the wrapper method, which is basically a call to the C icall, and
2852                  * an exception check.
2853                  */
2854                 costs = inline_method (cfg, info->wrapper_method, NULL,
2855                                                            args, NULL, il_offset, TRUE);
2856                 g_assert (costs > 0);
2857                 g_assert (!MONO_TYPE_IS_VOID (info->sig->ret));
2858
2859                 return args [0];
2860         } else {
2861                 return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2862         }
2863 }
2864  
2865 static MonoInst*
2866 mono_emit_widen_call_res (MonoCompile *cfg, MonoInst *ins, MonoMethodSignature *fsig)
2867 {
2868         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
2869                 if ((fsig->pinvoke || LLVM_ENABLED) && !fsig->ret->byref) {
2870                         int widen_op = -1;
2871
2872                         /* 
2873                          * Native code might return non register sized integers 
2874                          * without initializing the upper bits.
2875                          */
2876                         switch (mono_type_to_load_membase (cfg, fsig->ret)) {
2877                         case OP_LOADI1_MEMBASE:
2878                                 widen_op = OP_ICONV_TO_I1;
2879                                 break;
2880                         case OP_LOADU1_MEMBASE:
2881                                 widen_op = OP_ICONV_TO_U1;
2882                                 break;
2883                         case OP_LOADI2_MEMBASE:
2884                                 widen_op = OP_ICONV_TO_I2;
2885                                 break;
2886                         case OP_LOADU2_MEMBASE:
2887                                 widen_op = OP_ICONV_TO_U2;
2888                                 break;
2889                         default:
2890                                 break;
2891                         }
2892
2893                         if (widen_op != -1) {
2894                                 int dreg = alloc_preg (cfg);
2895                                 MonoInst *widen;
2896
2897                                 EMIT_NEW_UNALU (cfg, widen, widen_op, dreg, ins->dreg);
2898                                 widen->type = ins->type;
2899                                 ins = widen;
2900                         }
2901                 }
2902         }
2903
2904         return ins;
2905 }
2906
2907
2908 static void
2909 emit_method_access_failure (MonoCompile *cfg, MonoMethod *method, MonoMethod *cil_method)
2910 {
2911         MonoInst *args [16];
2912
2913         args [0] = emit_get_rgctx_method (cfg, mono_method_check_context_used (method), method, MONO_RGCTX_INFO_METHOD);
2914         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cil_method), cil_method, MONO_RGCTX_INFO_METHOD);
2915
2916         mono_emit_jit_icall (cfg, mono_throw_method_access, args);
2917 }
2918
2919 static MonoMethod*
2920 get_memcpy_method (void)
2921 {
2922         static MonoMethod *memcpy_method = NULL;
2923         if (!memcpy_method) {
2924                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
2925                 if (!memcpy_method)
2926                         g_error ("Old corlib found. Install a new one");
2927         }
2928         return memcpy_method;
2929 }
2930
2931 static void
2932 create_write_barrier_bitmap (MonoCompile *cfg, MonoClass *klass, unsigned *wb_bitmap, int offset)
2933 {
2934         MonoClassField *field;
2935         gpointer iter = NULL;
2936
2937         while ((field = mono_class_get_fields (klass, &iter))) {
2938                 int foffset;
2939
2940                 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
2941                         continue;
2942                 foffset = klass->valuetype ? field->offset - sizeof (MonoObject): field->offset;
2943                 if (mini_type_is_reference (mono_field_get_type (field))) {
2944                         g_assert ((foffset % SIZEOF_VOID_P) == 0);
2945                         *wb_bitmap |= 1 << ((offset + foffset) / SIZEOF_VOID_P);
2946                 } else {
2947                         MonoClass *field_class = mono_class_from_mono_type (field->type);
2948                         if (field_class->has_references)
2949                                 create_write_barrier_bitmap (cfg, field_class, wb_bitmap, offset + foffset);
2950                 }
2951         }
2952 }
2953
2954 static void
2955 emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value)
2956 {
2957         int card_table_shift_bits;
2958         gpointer card_table_mask;
2959         guint8 *card_table;
2960         MonoInst *dummy_use;
2961         int nursery_shift_bits;
2962         size_t nursery_size;
2963
2964         if (!cfg->gen_write_barriers)
2965                 return;
2966
2967         card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
2968
2969         mono_gc_get_nursery (&nursery_shift_bits, &nursery_size);
2970
2971         if (cfg->backend->have_card_table_wb && !cfg->compile_aot && card_table && nursery_shift_bits > 0 && !COMPILE_LLVM (cfg)) {
2972                 MonoInst *wbarrier;
2973
2974                 MONO_INST_NEW (cfg, wbarrier, OP_CARD_TABLE_WBARRIER);
2975                 wbarrier->sreg1 = ptr->dreg;
2976                 wbarrier->sreg2 = value->dreg;
2977                 MONO_ADD_INS (cfg->cbb, wbarrier);
2978         } else if (card_table && !cfg->compile_aot && !mono_gc_card_table_nursery_check ()) {
2979                 int offset_reg = alloc_preg (cfg);
2980                 int card_reg;
2981                 MonoInst *ins;
2982
2983                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, offset_reg, ptr->dreg, card_table_shift_bits);
2984                 if (card_table_mask)
2985                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, offset_reg, offset_reg, card_table_mask);
2986
2987                 /*We can't use PADD_IMM since the cardtable might end up in high addresses and amd64 doesn't support
2988                  * IMM's larger than 32bits.
2989                  */
2990                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
2991                 card_reg = ins->dreg;
2992
2993                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, offset_reg, offset_reg, card_reg);
2994                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, offset_reg, 0, 1);
2995         } else {
2996                 MonoMethod *write_barrier = mono_gc_get_write_barrier ();
2997                 mono_emit_method_call (cfg, write_barrier, &ptr, NULL);
2998         }
2999
3000         EMIT_NEW_DUMMY_USE (cfg, dummy_use, value);
3001 }
3002
3003 static gboolean
3004 mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align)
3005 {
3006         int dest_ptr_reg, tmp_reg, destreg, srcreg, offset;
3007         unsigned need_wb = 0;
3008
3009         if (align == 0)
3010                 align = 4;
3011
3012         /*types with references can't have alignment smaller than sizeof(void*) */
3013         if (align < SIZEOF_VOID_P)
3014                 return FALSE;
3015
3016         /*This value cannot be bigger than 32 due to the way we calculate the required wb bitmap.*/
3017         if (size > 32 * SIZEOF_VOID_P)
3018                 return FALSE;
3019
3020         create_write_barrier_bitmap (cfg, klass, &need_wb, 0);
3021
3022         /* We don't unroll more than 5 stores to avoid code bloat. */
3023         if (size > 5 * SIZEOF_VOID_P) {
3024                 /*This is harmless and simplify mono_gc_wbarrier_value_copy_bitmap */
3025                 size += (SIZEOF_VOID_P - 1);
3026                 size &= ~(SIZEOF_VOID_P - 1);
3027
3028                 EMIT_NEW_ICONST (cfg, iargs [2], size);
3029                 EMIT_NEW_ICONST (cfg, iargs [3], need_wb);
3030                 mono_emit_jit_icall (cfg, mono_gc_wbarrier_value_copy_bitmap, iargs);
3031                 return TRUE;
3032         }
3033
3034         destreg = iargs [0]->dreg;
3035         srcreg = iargs [1]->dreg;
3036         offset = 0;
3037
3038         dest_ptr_reg = alloc_preg (cfg);
3039         tmp_reg = alloc_preg (cfg);
3040
3041         /*tmp = dreg*/
3042         EMIT_NEW_UNALU (cfg, iargs [0], OP_MOVE, dest_ptr_reg, destreg);
3043
3044         while (size >= SIZEOF_VOID_P) {
3045                 MonoInst *load_inst;
3046                 MONO_INST_NEW (cfg, load_inst, OP_LOAD_MEMBASE);
3047                 load_inst->dreg = tmp_reg;
3048                 load_inst->inst_basereg = srcreg;
3049                 load_inst->inst_offset = offset;
3050                 MONO_ADD_INS (cfg->cbb, load_inst);
3051
3052                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg);
3053
3054                 if (need_wb & 0x1)
3055                         emit_write_barrier (cfg, iargs [0], load_inst);
3056
3057                 offset += SIZEOF_VOID_P;
3058                 size -= SIZEOF_VOID_P;
3059                 need_wb >>= 1;
3060
3061                 /*tmp += sizeof (void*)*/
3062                 if (size >= SIZEOF_VOID_P) {
3063                         NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dest_ptr_reg, dest_ptr_reg, SIZEOF_VOID_P);
3064                         MONO_ADD_INS (cfg->cbb, iargs [0]);
3065                 }
3066         }
3067
3068         /* Those cannot be references since size < sizeof (void*) */
3069         while (size >= 4) {
3070                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tmp_reg, srcreg, offset);
3071                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, tmp_reg);
3072                 offset += 4;
3073                 size -= 4;
3074         }
3075
3076         while (size >= 2) {
3077                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmp_reg, srcreg, offset);
3078                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, tmp_reg);
3079                 offset += 2;
3080                 size -= 2;
3081         }
3082
3083         while (size >= 1) {
3084                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmp_reg, srcreg, offset);
3085                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, tmp_reg);
3086                 offset += 1;
3087                 size -= 1;
3088         }
3089
3090         return TRUE;
3091 }
3092
3093 /*
3094  * Emit code to copy a valuetype of type @klass whose address is stored in
3095  * @src->dreg to memory whose address is stored at @dest->dreg.
3096  */
3097 void
3098 mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native)
3099 {
3100         MonoInst *iargs [4];
3101         int n;
3102         guint32 align = 0;
3103         MonoMethod *memcpy_method;
3104         MonoInst *size_ins = NULL;
3105         MonoInst *memcpy_ins = NULL;
3106
3107         g_assert (klass);
3108         if (cfg->gshared)
3109                 klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
3110
3111         /*
3112          * This check breaks with spilled vars... need to handle it during verification anyway.
3113          * g_assert (klass && klass == src->klass && klass == dest->klass);
3114          */
3115
3116         if (mini_is_gsharedvt_klass (klass)) {
3117                 g_assert (!native);
3118                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3119                 memcpy_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_MEMCPY);
3120         }
3121
3122         if (native)
3123                 n = mono_class_native_size (klass, &align);
3124         else
3125                 n = mono_class_value_size (klass, &align);
3126
3127         /* if native is true there should be no references in the struct */
3128         if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) {
3129                 /* Avoid barriers when storing to the stack */
3130                 if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
3131                           (dest->opcode == OP_LDADDR))) {
3132                         int context_used;
3133
3134                         iargs [0] = dest;
3135                         iargs [1] = src;
3136
3137                         context_used = mini_class_check_context_used (cfg, klass);
3138
3139                         /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
3140                         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
3141                                 return;
3142                         } else if (context_used) {
3143                                 iargs [2] = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3144                         }  else {
3145                                 iargs [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
3146                                 if (!cfg->compile_aot)
3147                                         mono_class_compute_gc_descriptor (klass);
3148                         }
3149
3150                         if (size_ins)
3151                                 mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
3152                         else
3153                                 mono_emit_jit_icall (cfg, mono_value_copy, iargs);
3154                         return;
3155                 }
3156         }
3157
3158         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 8) {
3159                 /* FIXME: Optimize the case when src/dest is OP_LDADDR */
3160                 mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, n, align);
3161         } else {
3162                 iargs [0] = dest;
3163                 iargs [1] = src;
3164                 if (size_ins)
3165                         iargs [2] = size_ins;
3166                 else
3167                         EMIT_NEW_ICONST (cfg, iargs [2], n);
3168                 
3169                 memcpy_method = get_memcpy_method ();
3170                 if (memcpy_ins)
3171                         mono_emit_calli (cfg, mono_method_signature (memcpy_method), iargs, memcpy_ins, NULL, NULL);
3172                 else
3173                         mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
3174         }
3175 }
3176
3177 static MonoMethod*
3178 get_memset_method (void)
3179 {
3180         static MonoMethod *memset_method = NULL;
3181         if (!memset_method) {
3182                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
3183                 if (!memset_method)
3184                         g_error ("Old corlib found. Install a new one");
3185         }
3186         return memset_method;
3187 }
3188
3189 void
3190 mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass)
3191 {
3192         MonoInst *iargs [3];
3193         int n;
3194         guint32 align;
3195         MonoMethod *memset_method;
3196         MonoInst *size_ins = NULL;
3197         MonoInst *bzero_ins = NULL;
3198         static MonoMethod *bzero_method;
3199
3200         /* FIXME: Optimize this for the case when dest is an LDADDR */
3201         mono_class_init (klass);
3202         if (mini_is_gsharedvt_klass (klass)) {
3203                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3204                 bzero_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_BZERO);
3205                 if (!bzero_method)
3206                         bzero_method = mono_class_get_method_from_name (mono_defaults.string_class, "bzero_aligned_1", 2);
3207                 g_assert (bzero_method);
3208                 iargs [0] = dest;
3209                 iargs [1] = size_ins;
3210                 mono_emit_calli (cfg, mono_method_signature (bzero_method), iargs, bzero_ins, NULL, NULL);
3211                 return;
3212         }
3213
3214         klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
3215
3216         n = mono_class_value_size (klass, &align);
3217
3218         if (n <= sizeof (gpointer) * 8) {
3219                 mini_emit_memset (cfg, dest->dreg, 0, n, 0, align);
3220         }
3221         else {
3222                 memset_method = get_memset_method ();
3223                 iargs [0] = dest;
3224                 EMIT_NEW_ICONST (cfg, iargs [1], 0);
3225                 EMIT_NEW_ICONST (cfg, iargs [2], n);
3226                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
3227         }
3228 }
3229
3230 /*
3231  * emit_get_rgctx:
3232  *
3233  *   Emit IR to return either the this pointer for instance method,
3234  * or the mrgctx for static methods.
3235  */
3236 static MonoInst*
3237 emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used)
3238 {
3239         MonoInst *this_ins = NULL;
3240
3241         g_assert (cfg->gshared);
3242
3243         if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&
3244                         !(context_used & MONO_GENERIC_CONTEXT_USED_METHOD) &&
3245                 !method->klass->valuetype)
3246                 EMIT_NEW_VARLOAD (cfg, this_ins, cfg->this_arg, &mono_defaults.object_class->byval_arg);
3247
3248         if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
3249                 MonoInst *mrgctx_loc, *mrgctx_var;
3250
3251                 g_assert (!this_ins);
3252                 g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
3253
3254                 mrgctx_loc = mono_get_vtable_var (cfg);
3255                 EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
3256
3257                 return mrgctx_var;
3258         } else if (method->flags & METHOD_ATTRIBUTE_STATIC || method->klass->valuetype) {
3259                 MonoInst *vtable_loc, *vtable_var;
3260
3261                 g_assert (!this_ins);
3262
3263                 vtable_loc = mono_get_vtable_var (cfg);
3264                 EMIT_NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
3265
3266                 if (method->is_inflated && mono_method_get_context (method)->method_inst) {
3267                         MonoInst *mrgctx_var = vtable_var;
3268                         int vtable_reg;
3269
3270                         vtable_reg = alloc_preg (cfg);
3271                         EMIT_NEW_LOAD_MEMBASE (cfg, vtable_var, OP_LOAD_MEMBASE, vtable_reg, mrgctx_var->dreg, MONO_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable));
3272                         vtable_var->type = STACK_PTR;
3273                 }
3274
3275                 return vtable_var;
3276         } else {
3277                 MonoInst *ins;
3278                 int vtable_reg;
3279         
3280                 vtable_reg = alloc_preg (cfg);
3281                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, vtable_reg, this_ins->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3282                 return ins;
3283         }
3284 }
3285
3286 static MonoJumpInfoRgctxEntry *
3287 mono_patch_info_rgctx_entry_new (MonoMemPool *mp, MonoMethod *method, gboolean in_mrgctx, MonoJumpInfoType patch_type, gconstpointer patch_data, MonoRgctxInfoType info_type)
3288 {
3289         MonoJumpInfoRgctxEntry *res = (MonoJumpInfoRgctxEntry *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoRgctxEntry));
3290         res->method = method;
3291         res->in_mrgctx = in_mrgctx;
3292         res->data = (MonoJumpInfo *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
3293         res->data->type = patch_type;
3294         res->data->data.target = patch_data;
3295         res->info_type = info_type;
3296
3297         return res;
3298 }
3299
3300 static inline MonoInst*
3301 emit_rgctx_fetch_inline (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3302 {
3303         MonoInst *args [16];
3304         MonoInst *call;
3305
3306         // FIXME: No fastpath since the slot is not a compile time constant
3307         args [0] = rgctx;
3308         EMIT_NEW_AOTCONST (cfg, args [1], MONO_PATCH_INFO_RGCTX_SLOT_INDEX, entry);
3309         if (entry->in_mrgctx)
3310                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3311         else
3312                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3313         return call;
3314 #if 0
3315         /*
3316          * FIXME: This can be called during decompose, which is a problem since it creates
3317          * new bblocks.
3318          * Also, the fastpath doesn't work since the slot number is dynamically allocated.
3319          */
3320         int i, slot, depth, index, rgctx_reg, val_reg, res_reg;
3321         gboolean mrgctx;
3322         MonoBasicBlock *is_null_bb, *end_bb;
3323         MonoInst *res, *ins, *call;
3324         MonoInst *args[16];
3325
3326         slot = mini_get_rgctx_entry_slot (entry);
3327
3328         mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot);
3329         index = MONO_RGCTX_SLOT_INDEX (slot);
3330         if (mrgctx)
3331                 index += MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
3332         for (depth = 0; ; ++depth) {
3333                 int size = mono_class_rgctx_get_array_size (depth, mrgctx);
3334
3335                 if (index < size - 1)
3336                         break;
3337                 index -= size - 1;
3338         }
3339
3340         NEW_BBLOCK (cfg, end_bb);
3341         NEW_BBLOCK (cfg, is_null_bb);
3342
3343         if (mrgctx) {
3344                 rgctx_reg = rgctx->dreg;
3345         } else {
3346                 rgctx_reg = alloc_preg (cfg);
3347
3348                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, rgctx_reg, rgctx->dreg, MONO_STRUCT_OFFSET (MonoVTable, runtime_generic_context));
3349                 // FIXME: Avoid this check by allocating the table when the vtable is created etc.
3350                 NEW_BBLOCK (cfg, is_null_bb);
3351
3352                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3353                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3354         }
3355
3356         for (i = 0; i < depth; ++i) {
3357                 int array_reg = alloc_preg (cfg);
3358
3359                 /* load ptr to next array */
3360                 if (mrgctx && i == 0)
3361                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT);
3362                 else
3363                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, 0);
3364                 rgctx_reg = array_reg;
3365                 /* is the ptr null? */
3366                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3367                 /* if yes, jump to actual trampoline */
3368                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3369         }
3370
3371         /* fetch slot */
3372         val_reg = alloc_preg (cfg);
3373         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, val_reg, rgctx_reg, (index + 1) * sizeof (gpointer));
3374         /* is the slot null? */
3375         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, val_reg, 0);
3376         /* if yes, jump to actual trampoline */
3377         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3378
3379         /* Fastpath */
3380         res_reg = alloc_preg (cfg);
3381         MONO_INST_NEW (cfg, ins, OP_MOVE);
3382         ins->dreg = res_reg;
3383         ins->sreg1 = val_reg;
3384         MONO_ADD_INS (cfg->cbb, ins);
3385         res = ins;
3386         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3387
3388         /* Slowpath */
3389         MONO_START_BB (cfg, is_null_bb);
3390         args [0] = rgctx;
3391         EMIT_NEW_ICONST (cfg, args [1], index);
3392         if (mrgctx)
3393                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3394         else
3395                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3396         MONO_INST_NEW (cfg, ins, OP_MOVE);
3397         ins->dreg = res_reg;
3398         ins->sreg1 = call->dreg;
3399         MONO_ADD_INS (cfg->cbb, ins);
3400         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3401
3402         MONO_START_BB (cfg, end_bb);
3403
3404         return res;
3405 #endif
3406 }
3407
3408 /*
3409  * emit_rgctx_fetch:
3410  *
3411  *   Emit IR to load the value of the rgctx entry ENTRY from the rgctx
3412  * given by RGCTX.
3413  */
3414 static inline MonoInst*
3415 emit_rgctx_fetch (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3416 {
3417         if (cfg->llvm_only)
3418                 return emit_rgctx_fetch_inline (cfg, rgctx, entry);
3419         else
3420                 return mono_emit_abs_call (cfg, MONO_PATCH_INFO_RGCTX_FETCH, entry, helper_sig_rgctx_lazy_fetch_trampoline, &rgctx);
3421 }
3422
3423 MonoInst*
3424 mini_emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
3425                                           MonoClass *klass, MonoRgctxInfoType rgctx_type)
3426 {
3427         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);
3428         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3429
3430         return emit_rgctx_fetch (cfg, rgctx, entry);
3431 }
3432
3433 static MonoInst*
3434 emit_get_rgctx_sig (MonoCompile *cfg, int context_used,
3435                                         MonoMethodSignature *sig, MonoRgctxInfoType rgctx_type)
3436 {
3437         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);
3438         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3439
3440         return emit_rgctx_fetch (cfg, rgctx, entry);
3441 }
3442
3443 static MonoInst*
3444 emit_get_rgctx_gsharedvt_call (MonoCompile *cfg, int context_used,
3445                                                            MonoMethodSignature *sig, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3446 {
3447         MonoJumpInfoGSharedVtCall *call_info;
3448         MonoJumpInfoRgctxEntry *entry;
3449         MonoInst *rgctx;
3450
3451         call_info = (MonoJumpInfoGSharedVtCall *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoGSharedVtCall));
3452         call_info->sig = sig;
3453         call_info->method = cmethod;
3454
3455         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);
3456         rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3457
3458         return emit_rgctx_fetch (cfg, rgctx, entry);
3459 }
3460
3461 /*
3462  * emit_get_rgctx_virt_method:
3463  *
3464  *   Return data for method VIRT_METHOD for a receiver of type KLASS.
3465  */
3466 static MonoInst*
3467 emit_get_rgctx_virt_method (MonoCompile *cfg, int context_used,
3468                                                         MonoClass *klass, MonoMethod *virt_method, MonoRgctxInfoType rgctx_type)
3469 {
3470         MonoJumpInfoVirtMethod *info;
3471         MonoJumpInfoRgctxEntry *entry;
3472         MonoInst *rgctx;
3473
3474         info = (MonoJumpInfoVirtMethod *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoVirtMethod));
3475         info->klass = klass;
3476         info->method = virt_method;
3477
3478         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);
3479         rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3480
3481         return emit_rgctx_fetch (cfg, rgctx, entry);
3482 }
3483
3484 static MonoInst*
3485 emit_get_rgctx_gsharedvt_method (MonoCompile *cfg, int context_used,
3486                                                                  MonoMethod *cmethod, MonoGSharedVtMethodInfo *info)
3487 {
3488         MonoJumpInfoRgctxEntry *entry;
3489         MonoInst *rgctx;
3490
3491         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);
3492         rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3493
3494         return emit_rgctx_fetch (cfg, rgctx, entry);
3495 }
3496
3497 /*
3498  * emit_get_rgctx_method:
3499  *
3500  *   Emit IR to load the property RGCTX_TYPE of CMETHOD. If context_used is 0, emit
3501  * normal constants, else emit a load from the rgctx.
3502  */
3503 static MonoInst*
3504 emit_get_rgctx_method (MonoCompile *cfg, int context_used,
3505                                            MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3506 {
3507         if (!context_used) {
3508                 MonoInst *ins;
3509
3510                 switch (rgctx_type) {
3511                 case MONO_RGCTX_INFO_METHOD:
3512                         EMIT_NEW_METHODCONST (cfg, ins, cmethod);
3513                         return ins;
3514                 case MONO_RGCTX_INFO_METHOD_RGCTX:
3515                         EMIT_NEW_METHOD_RGCTX_CONST (cfg, ins, cmethod);
3516                         return ins;
3517                 default:
3518                         g_assert_not_reached ();
3519                 }
3520         } else {
3521                 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);
3522                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3523
3524                 return emit_rgctx_fetch (cfg, rgctx, entry);
3525         }
3526 }
3527
3528 static MonoInst*
3529 emit_get_rgctx_field (MonoCompile *cfg, int context_used,
3530                                           MonoClassField *field, MonoRgctxInfoType rgctx_type)
3531 {
3532         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);
3533         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3534
3535         return emit_rgctx_fetch (cfg, rgctx, entry);
3536 }
3537
3538 static int
3539 get_gsharedvt_info_slot (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3540 {
3541         MonoGSharedVtMethodInfo *info = cfg->gsharedvt_info;
3542         MonoRuntimeGenericContextInfoTemplate *template_;
3543         int i, idx;
3544
3545         g_assert (info);
3546
3547         for (i = 0; i < info->num_entries; ++i) {
3548                 MonoRuntimeGenericContextInfoTemplate *otemplate = &info->entries [i];
3549
3550                 if (otemplate->info_type == rgctx_type && otemplate->data == data && rgctx_type != MONO_RGCTX_INFO_LOCAL_OFFSET)
3551                         return i;
3552         }
3553
3554         if (info->num_entries == info->count_entries) {
3555                 MonoRuntimeGenericContextInfoTemplate *new_entries;
3556                 int new_count_entries = info->count_entries ? info->count_entries * 2 : 16;
3557
3558                 new_entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * new_count_entries);
3559
3560                 memcpy (new_entries, info->entries, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
3561                 info->entries = new_entries;
3562                 info->count_entries = new_count_entries;
3563         }
3564
3565         idx = info->num_entries;
3566         template_ = &info->entries [idx];
3567         template_->info_type = rgctx_type;
3568         template_->data = data;
3569
3570         info->num_entries ++;
3571
3572         return idx;
3573 }
3574
3575 /*
3576  * emit_get_gsharedvt_info:
3577  *
3578  *   This is similar to emit_get_rgctx_.., but loads the data from the gsharedvt info var instead of calling an rgctx fetch trampoline.
3579  */
3580 static MonoInst*
3581 emit_get_gsharedvt_info (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3582 {
3583         MonoInst *ins;
3584         int idx, dreg;
3585
3586         idx = get_gsharedvt_info_slot (cfg, data, rgctx_type);
3587         /* Load info->entries [idx] */
3588         dreg = alloc_preg (cfg);
3589         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, cfg->gsharedvt_info_var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
3590
3591         return ins;
3592 }
3593
3594 static MonoInst*
3595 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type)
3596 {
3597         return emit_get_gsharedvt_info (cfg, &klass->byval_arg, rgctx_type);
3598 }
3599
3600 /*
3601  * On return the caller must check @klass for load errors.
3602  */
3603 static void
3604 emit_class_init (MonoCompile *cfg, MonoClass *klass)
3605 {
3606         MonoInst *vtable_arg;
3607         int context_used;
3608
3609         context_used = mini_class_check_context_used (cfg, klass);
3610
3611         if (context_used) {
3612                 vtable_arg = mini_emit_get_rgctx_klass (cfg, context_used,
3613                                                                                    klass, MONO_RGCTX_INFO_VTABLE);
3614         } else {
3615                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3616
3617                 if (!vtable)
3618                         return;
3619                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
3620         }
3621
3622         if (!COMPILE_LLVM (cfg) && cfg->backend->have_op_generic_class_init) {
3623                 MonoInst *ins;
3624
3625                 /*
3626                  * Using an opcode instead of emitting IR here allows the hiding of the call inside the opcode,
3627                  * so this doesn't have to clobber any regs and it doesn't break basic blocks.
3628                  */
3629                 MONO_INST_NEW (cfg, ins, OP_GENERIC_CLASS_INIT);
3630                 ins->sreg1 = vtable_arg->dreg;
3631                 MONO_ADD_INS (cfg->cbb, ins);
3632         } else {
3633                 int inited_reg;
3634                 MonoBasicBlock *inited_bb;
3635                 MonoInst *args [16];
3636
3637                 inited_reg = alloc_ireg (cfg);
3638
3639                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, inited_reg, vtable_arg->dreg, MONO_STRUCT_OFFSET (MonoVTable, initialized));
3640
3641                 NEW_BBLOCK (cfg, inited_bb);
3642
3643                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, inited_reg, 0);
3644                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, inited_bb);
3645
3646                 args [0] = vtable_arg;
3647                 mono_emit_jit_icall (cfg, mono_generic_class_init, args);
3648
3649                 MONO_START_BB (cfg, inited_bb);
3650         }
3651 }
3652
3653 static void
3654 emit_seq_point (MonoCompile *cfg, MonoMethod *method, guint8* ip, gboolean intr_loc, gboolean nonempty_stack)
3655 {
3656         MonoInst *ins;
3657
3658         if (cfg->gen_seq_points && cfg->method == method) {
3659                 NEW_SEQ_POINT (cfg, ins, ip - cfg->header->code, intr_loc);
3660                 if (nonempty_stack)
3661                         ins->flags |= MONO_INST_NONEMPTY_STACK;
3662                 MONO_ADD_INS (cfg->cbb, ins);
3663         }
3664 }
3665
3666 void
3667 mini_save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean null_check)
3668 {
3669         if (mini_get_debug_options ()->better_cast_details) {
3670                 int vtable_reg = alloc_preg (cfg);
3671                 int klass_reg = alloc_preg (cfg);
3672                 MonoBasicBlock *is_null_bb = NULL;
3673                 MonoInst *tls_get;
3674                 int to_klass_reg, context_used;
3675
3676                 if (null_check) {
3677                         NEW_BBLOCK (cfg, is_null_bb);
3678
3679                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3680                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3681                 }
3682
3683                 tls_get = mono_get_jit_tls_intrinsic (cfg);
3684                 if (!tls_get) {
3685                         fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
3686                         exit (1);
3687                 }
3688
3689                 MONO_ADD_INS (cfg->cbb, tls_get);
3690                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3691                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3692
3693                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
3694
3695                 context_used = mini_class_check_context_used (cfg, klass);
3696                 if (context_used) {
3697                         MonoInst *class_ins;
3698
3699                         class_ins = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3700                         to_klass_reg = class_ins->dreg;
3701                 } else {
3702                         to_klass_reg = alloc_preg (cfg);
3703                         MONO_EMIT_NEW_CLASSCONST (cfg, to_klass_reg, klass);
3704                 }
3705                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
3706
3707                 if (null_check)
3708                         MONO_START_BB (cfg, is_null_bb);
3709         }
3710 }
3711
3712 void
3713 mini_reset_cast_details (MonoCompile *cfg)
3714 {
3715         /* Reset the variables holding the cast details */
3716         if (mini_get_debug_options ()->better_cast_details) {
3717                 MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
3718
3719                 MONO_ADD_INS (cfg->cbb, tls_get);
3720                 /* It is enough to reset the from field */
3721                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
3722         }
3723 }
3724
3725 /*
3726  * On return the caller must check @array_class for load errors
3727  */
3728 static void
3729 mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_class)
3730 {
3731         int vtable_reg = alloc_preg (cfg);
3732         int context_used;
3733
3734         context_used = mini_class_check_context_used (cfg, array_class);
3735
3736         mini_save_cast_details (cfg, array_class, obj->dreg, FALSE);
3737
3738         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3739
3740         if (cfg->opt & MONO_OPT_SHARED) {
3741                 int class_reg = alloc_preg (cfg);
3742                 MonoInst *ins;
3743
3744                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, class_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3745                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, array_class);
3746                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, class_reg, ins->dreg);
3747         } else if (context_used) {
3748                 MonoInst *vtable_ins;
3749
3750                 vtable_ins = mini_emit_get_rgctx_klass (cfg, context_used, array_class, MONO_RGCTX_INFO_VTABLE);
3751                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vtable_ins->dreg);
3752         } else {
3753                 if (cfg->compile_aot) {
3754                         int vt_reg;
3755                         MonoVTable *vtable;
3756
3757                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3758                                 return;
3759                         vt_reg = alloc_preg (cfg);
3760                         MONO_EMIT_NEW_VTABLECONST (cfg, vt_reg, vtable);
3761                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vt_reg);
3762                 } else {
3763                         MonoVTable *vtable;
3764                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3765                                 return;
3766                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vtable);
3767                 }
3768         }
3769         
3770         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
3771
3772         mini_reset_cast_details (cfg);
3773 }
3774
3775 /**
3776  * Handles unbox of a Nullable<T>. If context_used is non zero, then shared 
3777  * generic code is generated.
3778  */
3779 static MonoInst*
3780 handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int context_used)
3781 {
3782         MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
3783
3784         if (context_used) {
3785                 MonoInst *rgctx, *addr;
3786
3787                 /* FIXME: What if the class is shared?  We might not
3788                    have to get the address of the method from the
3789                    RGCTX. */
3790                 addr = emit_get_rgctx_method (cfg, context_used, method,
3791                                                                           MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
3792                 if (cfg->llvm_only) {
3793                         cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, mono_method_signature (method));
3794                         return emit_llvmonly_calli (cfg, mono_method_signature (method), &val, addr);
3795                 } else {
3796                         rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
3797
3798                         return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
3799                 }
3800         } else {
3801                 gboolean pass_vtable, pass_mrgctx;
3802                 MonoInst *rgctx_arg = NULL;
3803
3804                 check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
3805                 g_assert (!pass_mrgctx);
3806
3807                 if (pass_vtable) {
3808                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
3809
3810                         g_assert (vtable);
3811                         EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
3812                 }
3813
3814                 return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
3815         }
3816 }
3817
3818 static MonoInst*
3819 handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_used)
3820 {
3821         MonoInst *add;
3822         int obj_reg;
3823         int vtable_reg = alloc_dreg (cfg ,STACK_PTR);
3824         int klass_reg = alloc_dreg (cfg ,STACK_PTR);
3825         int eclass_reg = alloc_dreg (cfg ,STACK_PTR);
3826         int rank_reg = alloc_dreg (cfg ,STACK_I4);
3827
3828         obj_reg = sp [0]->dreg;
3829         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3830         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
3831
3832         /* FIXME: generics */
3833         g_assert (klass->rank == 0);
3834                         
3835         // Check rank == 0
3836         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 0);
3837         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3838
3839         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3840         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, element_class));
3841
3842         if (context_used) {
3843                 MonoInst *element_class;
3844
3845                 /* This assertion is from the unboxcast insn */
3846                 g_assert (klass->rank == 0);
3847
3848                 element_class = mini_emit_get_rgctx_klass (cfg, context_used,
3849                                 klass, MONO_RGCTX_INFO_ELEMENT_KLASS);
3850
3851                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, eclass_reg, element_class->dreg);
3852                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3853         } else {
3854                 mini_save_cast_details (cfg, klass->element_class, obj_reg, FALSE);
3855                 mini_emit_class_check (cfg, eclass_reg, klass->element_class);
3856                 mini_reset_cast_details (cfg);
3857         }
3858
3859         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), obj_reg, sizeof (MonoObject));
3860         MONO_ADD_INS (cfg->cbb, add);
3861         add->type = STACK_MP;
3862         add->klass = klass;
3863
3864         return add;
3865 }
3866
3867 static MonoInst*
3868 handle_unbox_gsharedvt (MonoCompile *cfg, MonoClass *klass, MonoInst *obj)
3869 {
3870         MonoInst *addr, *klass_inst, *is_ref, *args[16];
3871         MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
3872         MonoInst *ins;
3873         int dreg, addr_reg;
3874
3875         klass_inst = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_KLASS);
3876
3877         /* obj */
3878         args [0] = obj;
3879
3880         /* klass */
3881         args [1] = klass_inst;
3882
3883         /* CASTCLASS */
3884         obj = mono_emit_jit_icall (cfg, mono_object_castclass_unbox, args);
3885
3886         NEW_BBLOCK (cfg, is_ref_bb);
3887         NEW_BBLOCK (cfg, is_nullable_bb);
3888         NEW_BBLOCK (cfg, end_bb);
3889         is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
3890         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
3891         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
3892
3893         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
3894         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
3895
3896         /* This will contain either the address of the unboxed vtype, or an address of the temporary where the ref is stored */
3897         addr_reg = alloc_dreg (cfg, STACK_MP);
3898
3899         /* Non-ref case */
3900         /* UNBOX */
3901         NEW_BIALU_IMM (cfg, addr, OP_ADD_IMM, addr_reg, obj->dreg, sizeof (MonoObject));
3902         MONO_ADD_INS (cfg->cbb, addr);
3903
3904         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3905
3906         /* Ref case */
3907         MONO_START_BB (cfg, is_ref_bb);
3908
3909         /* Save the ref to a temporary */
3910         dreg = alloc_ireg (cfg);
3911         EMIT_NEW_VARLOADA_VREG (cfg, addr, dreg, &klass->byval_arg);
3912         addr->dreg = addr_reg;
3913         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, obj->dreg);
3914         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3915
3916         /* Nullable case */
3917         MONO_START_BB (cfg, is_nullable_bb);
3918
3919         {
3920                 MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX);
3921                 MonoInst *unbox_call;
3922                 MonoMethodSignature *unbox_sig;
3923
3924                 unbox_sig = (MonoMethodSignature *)mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
3925                 unbox_sig->ret = &klass->byval_arg;
3926                 unbox_sig->param_count = 1;
3927                 unbox_sig->params [0] = &mono_defaults.object_class->byval_arg;
3928
3929                 if (cfg->llvm_only)
3930                         unbox_call = emit_llvmonly_calli (cfg, unbox_sig, &obj, addr);
3931                 else
3932                         unbox_call = mono_emit_calli (cfg, unbox_sig, &obj, addr, NULL, NULL);
3933
3934                 EMIT_NEW_VARLOADA_VREG (cfg, addr, unbox_call->dreg, &klass->byval_arg);
3935                 addr->dreg = addr_reg;
3936         }
3937
3938         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3939
3940         /* End */
3941         MONO_START_BB (cfg, end_bb);
3942
3943         /* LDOBJ */
3944         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr_reg, 0);
3945
3946         return ins;
3947 }
3948
3949 /*
3950  * Returns NULL and set the cfg exception on error.
3951  */
3952 static MonoInst*
3953 handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_used)
3954 {
3955         MonoInst *iargs [2];
3956         void *alloc_ftn;
3957
3958         if (context_used) {
3959                 MonoInst *data;
3960                 MonoRgctxInfoType rgctx_info;
3961                 MonoInst *iargs [2];
3962                 gboolean known_instance_size = !mini_is_gsharedvt_klass (klass);
3963
3964                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (klass, for_box, known_instance_size);
3965
3966                 if (cfg->opt & MONO_OPT_SHARED)
3967                         rgctx_info = MONO_RGCTX_INFO_KLASS;
3968                 else
3969                         rgctx_info = MONO_RGCTX_INFO_VTABLE;
3970                 data = mini_emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
3971
3972                 if (cfg->opt & MONO_OPT_SHARED) {
3973                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
3974                         iargs [1] = data;
3975                         alloc_ftn = ves_icall_object_new;
3976                 } else {
3977                         iargs [0] = data;
3978                         alloc_ftn = ves_icall_object_new_specific;
3979                 }
3980
3981                 if (managed_alloc && !(cfg->opt & MONO_OPT_SHARED)) {
3982                         if (known_instance_size) {
3983                                 int size = mono_class_instance_size (klass);
3984                                 if (size < sizeof (MonoObject))
3985                                         g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
3986
3987                                 EMIT_NEW_ICONST (cfg, iargs [1], size);
3988                         }
3989                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
3990                 }
3991
3992                 return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
3993         }
3994
3995         if (cfg->opt & MONO_OPT_SHARED) {
3996                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
3997                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
3998
3999                 alloc_ftn = ves_icall_object_new;
4000         } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !mono_class_is_ginst (klass)) {
4001                 /* This happens often in argument checking code, eg. throw new FooException... */
4002                 /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
4003                 EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
4004                 return mono_emit_jit_icall (cfg, mono_helper_newobj_mscorlib, iargs);
4005         } else {
4006                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
4007                 MonoMethod *managed_alloc = NULL;
4008                 gboolean pass_lw;
4009
4010                 if (!vtable) {
4011                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4012                         cfg->exception_ptr = klass;
4013                         return NULL;
4014                 }
4015
4016                 managed_alloc = mono_gc_get_managed_allocator (klass, for_box, TRUE);
4017
4018                 if (managed_alloc) {
4019                         int size = mono_class_instance_size (klass);
4020                         if (size < sizeof (MonoObject))
4021                                 g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4022
4023                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4024                         EMIT_NEW_ICONST (cfg, iargs [1], size);
4025                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4026                 }
4027                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
4028                 if (pass_lw) {
4029                         guint32 lw = vtable->klass->instance_size;
4030                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
4031                         EMIT_NEW_ICONST (cfg, iargs [0], lw);
4032                         EMIT_NEW_VTABLECONST (cfg, iargs [1], vtable);
4033                 }
4034                 else {
4035                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4036                 }
4037         }
4038
4039         return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4040 }
4041         
4042 /*
4043  * Returns NULL and set the cfg exception on error.
4044  */     
4045 static MonoInst*
4046 handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used)
4047 {
4048         MonoInst *alloc, *ins;
4049
4050         if (mono_class_is_nullable (klass)) {
4051                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
4052
4053                 if (context_used) {
4054                         if (cfg->llvm_only && cfg->gsharedvt) {
4055                                 MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4056                                                                                                                 MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4057                                 return emit_llvmonly_calli (cfg, mono_method_signature (method), &val, addr);
4058                         } else {
4059                                 /* FIXME: What if the class is shared?  We might not
4060                                    have to get the method address from the RGCTX. */
4061                                 MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4062                                                                                                                 MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4063                                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->method, context_used);
4064
4065                                 return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
4066                         }
4067                 } else {
4068                         gboolean pass_vtable, pass_mrgctx;
4069                         MonoInst *rgctx_arg = NULL;
4070
4071                         check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
4072                         g_assert (!pass_mrgctx);
4073
4074                         if (pass_vtable) {
4075                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4076
4077                                 g_assert (vtable);
4078                                 EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4079                         }
4080
4081                         return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4082                 }
4083         }
4084
4085         if (mini_is_gsharedvt_klass (klass)) {
4086                 MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4087                 MonoInst *res, *is_ref, *src_var, *addr;
4088                 int dreg;
4089
4090                 dreg = alloc_ireg (cfg);
4091
4092                 NEW_BBLOCK (cfg, is_ref_bb);
4093                 NEW_BBLOCK (cfg, is_nullable_bb);
4094                 NEW_BBLOCK (cfg, end_bb);
4095                 is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4096                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
4097                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4098
4099                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
4100                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4101
4102                 /* Non-ref case */
4103                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4104                 if (!alloc)
4105                         return NULL;
4106                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4107                 ins->opcode = OP_STOREV_MEMBASE;
4108
4109                 EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, alloc->dreg);
4110                 res->type = STACK_OBJ;
4111                 res->klass = klass;
4112                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4113                 
4114                 /* Ref case */
4115                 MONO_START_BB (cfg, is_ref_bb);
4116
4117                 /* val is a vtype, so has to load the value manually */
4118                 src_var = get_vreg_to_inst (cfg, val->dreg);
4119                 if (!src_var)
4120                         src_var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, val->dreg);
4121                 EMIT_NEW_VARLOADA (cfg, addr, src_var, src_var->inst_vtype);
4122                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, addr->dreg, 0);
4123                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4124
4125                 /* Nullable case */
4126                 MONO_START_BB (cfg, is_nullable_bb);
4127
4128                 {
4129                         MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass,
4130                                                                                                         MONO_RGCTX_INFO_NULLABLE_CLASS_BOX);
4131                         MonoInst *box_call;
4132                         MonoMethodSignature *box_sig;
4133
4134                         /*
4135                          * klass is Nullable<T>, need to call Nullable<T>.Box () using a gsharedvt signature, but we cannot
4136                          * construct that method at JIT time, so have to do things by hand.
4137                          */
4138                         box_sig = (MonoMethodSignature *)mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4139                         box_sig->ret = &mono_defaults.object_class->byval_arg;
4140                         box_sig->param_count = 1;
4141                         box_sig->params [0] = &klass->byval_arg;
4142
4143                         if (cfg->llvm_only)
4144                                 box_call = emit_llvmonly_calli (cfg, box_sig, &val, addr);
4145                         else
4146                                 box_call = mono_emit_calli (cfg, box_sig, &val, addr, NULL, NULL);
4147                         EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, box_call->dreg);
4148                         res->type = STACK_OBJ;
4149                         res->klass = klass;
4150                 }
4151
4152                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4153
4154                 MONO_START_BB (cfg, end_bb);
4155
4156                 return res;
4157         } else {
4158                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4159                 if (!alloc)
4160                         return NULL;
4161
4162                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4163                 return alloc;
4164         }
4165 }
4166
4167 static GHashTable* direct_icall_type_hash;
4168
4169 static gboolean
4170 icall_is_direct_callable (MonoCompile *cfg, MonoMethod *cmethod)
4171 {
4172         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
4173         if (!direct_icalls_enabled (cfg))
4174                 return FALSE;
4175
4176         /*
4177          * An icall is directly callable if it doesn't directly or indirectly call mono_raise_exception ().
4178          * Whitelist a few icalls for now.
4179          */
4180         if (!direct_icall_type_hash) {
4181                 GHashTable *h = g_hash_table_new (g_str_hash, g_str_equal);
4182
4183                 g_hash_table_insert (h, (char*)"Decimal", GUINT_TO_POINTER (1));
4184                 g_hash_table_insert (h, (char*)"Number", GUINT_TO_POINTER (1));
4185                 g_hash_table_insert (h, (char*)"Buffer", GUINT_TO_POINTER (1));
4186                 g_hash_table_insert (h, (char*)"Monitor", GUINT_TO_POINTER (1));
4187                 mono_memory_barrier ();
4188                 direct_icall_type_hash = h;
4189         }
4190
4191         if (cmethod->klass == mono_defaults.math_class)
4192                 return TRUE;
4193         /* No locking needed */
4194         if (cmethod->klass->image == mono_defaults.corlib && g_hash_table_lookup (direct_icall_type_hash, cmethod->klass->name))
4195                 return TRUE;
4196         return FALSE;
4197 }
4198
4199 static gboolean
4200 method_needs_stack_walk (MonoCompile *cfg, MonoMethod *cmethod)
4201 {
4202         if (cmethod->klass == mono_defaults.systemtype_class) {
4203                 if (!strcmp (cmethod->name, "GetType"))
4204                         return TRUE;
4205         }
4206         return FALSE;
4207 }
4208
4209 static G_GNUC_UNUSED MonoInst*
4210 handle_enum_has_flag (MonoCompile *cfg, MonoClass *klass, MonoInst *enum_this, MonoInst *enum_flag)
4211 {
4212         MonoType *enum_type = mono_type_get_underlying_type (&klass->byval_arg);
4213         guint32 load_opc = mono_type_to_load_membase (cfg, enum_type);
4214         gboolean is_i4;
4215
4216         switch (enum_type->type) {
4217         case MONO_TYPE_I8:
4218         case MONO_TYPE_U8:
4219 #if SIZEOF_REGISTER == 8
4220         case MONO_TYPE_I:
4221         case MONO_TYPE_U:
4222 #endif
4223                 is_i4 = FALSE;
4224                 break;
4225         default:
4226                 is_i4 = TRUE;
4227                 break;
4228         }
4229
4230         {
4231                 MonoInst *load, *and_, *cmp, *ceq;
4232                 int enum_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4233                 int and_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4234                 int dest_reg = alloc_ireg (cfg);
4235
4236                 EMIT_NEW_LOAD_MEMBASE (cfg, load, load_opc, enum_reg, enum_this->dreg, 0);
4237                 EMIT_NEW_BIALU (cfg, and_, is_i4 ? OP_IAND : OP_LAND, and_reg, enum_reg, enum_flag->dreg);
4238                 EMIT_NEW_BIALU (cfg, cmp, is_i4 ? OP_ICOMPARE : OP_LCOMPARE, -1, and_reg, enum_flag->dreg);
4239                 EMIT_NEW_UNALU (cfg, ceq, is_i4 ? OP_ICEQ : OP_LCEQ, dest_reg, -1);
4240
4241                 ceq->type = STACK_I4;
4242
4243                 if (!is_i4) {
4244                         load = mono_decompose_opcode (cfg, load);
4245                         and_ = mono_decompose_opcode (cfg, and_);
4246                         cmp = mono_decompose_opcode (cfg, cmp);
4247                         ceq = mono_decompose_opcode (cfg, ceq);
4248                 }
4249
4250                 return ceq;
4251         }
4252 }
4253
4254 /*
4255  * Returns NULL and set the cfg exception on error.
4256  */
4257 static G_GNUC_UNUSED MonoInst*
4258 handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used, gboolean virtual_)
4259 {
4260         MonoInst *ptr;
4261         int dreg;
4262         gpointer trampoline;
4263         MonoInst *obj, *method_ins, *tramp_ins;
4264         MonoDomain *domain;
4265         guint8 **code_slot;
4266
4267         if (virtual_ && !cfg->llvm_only) {
4268                 MonoMethod *invoke = mono_get_delegate_invoke (klass);
4269                 g_assert (invoke);
4270
4271                 if (!mono_get_delegate_virtual_invoke_impl (mono_method_signature (invoke), context_used ? NULL : method))
4272                         return NULL;
4273         }
4274
4275         obj = handle_alloc (cfg, klass, FALSE, mono_class_check_context_used (klass));
4276         if (!obj)
4277                 return NULL;
4278
4279         /* Inline the contents of mono_delegate_ctor */
4280
4281         /* Set target field */
4282         /* Optimize away setting of NULL target */
4283         if (!MONO_INS_IS_PCONST_NULL (target)) {
4284                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
4285                 if (cfg->gen_write_barriers) {
4286                         dreg = alloc_preg (cfg);
4287                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target));
4288                         emit_write_barrier (cfg, ptr, target);
4289                 }
4290         }
4291
4292         /* Set method field */
4293         method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
4294         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
4295
4296         /* 
4297          * To avoid looking up the compiled code belonging to the target method
4298          * in mono_delegate_trampoline (), we allocate a per-domain memory slot to
4299          * store it, and we fill it after the method has been compiled.
4300          */
4301         if (!method->dynamic && !(cfg->opt & MONO_OPT_SHARED)) {
4302                 MonoInst *code_slot_ins;
4303
4304                 if (context_used) {
4305                         code_slot_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD_DELEGATE_CODE);
4306                 } else {
4307                         domain = mono_domain_get ();
4308                         mono_domain_lock (domain);
4309                         if (!domain_jit_info (domain)->method_code_hash)
4310                                 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
4311                         code_slot = (guint8 **)g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
4312                         if (!code_slot) {
4313                                 code_slot = (guint8 **)mono_domain_alloc0 (domain, sizeof (gpointer));
4314                                 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
4315                         }
4316                         mono_domain_unlock (domain);
4317
4318                         code_slot_ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHOD_CODE_SLOT, method);
4319                 }
4320                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);                
4321         }
4322
4323         if (cfg->llvm_only) {
4324                 MonoInst *args [16];
4325
4326                 if (virtual_) {
4327                         args [0] = obj;
4328                         args [1] = target;
4329                         args [2] = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
4330                         mono_emit_jit_icall (cfg, mono_llvmonly_init_delegate_virtual, args);
4331                 } else {
4332                         args [0] = obj;
4333                         mono_emit_jit_icall (cfg, mono_llvmonly_init_delegate, args);
4334                 }
4335
4336                 return obj;
4337         }
4338
4339         if (cfg->compile_aot) {
4340                 MonoDelegateClassMethodPair *del_tramp;
4341
4342                 del_tramp = (MonoDelegateClassMethodPair *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoDelegateClassMethodPair));
4343                 del_tramp->klass = klass;
4344                 del_tramp->method = context_used ? NULL : method;
4345                 del_tramp->is_virtual = virtual_;
4346                 EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_DELEGATE_TRAMPOLINE, del_tramp);
4347         } else {
4348                 if (virtual_)
4349                         trampoline = mono_create_delegate_virtual_trampoline (cfg->domain, klass, context_used ? NULL : method);
4350                 else
4351                         trampoline = mono_create_delegate_trampoline_info (cfg->domain, klass, context_used ? NULL : method);
4352                 EMIT_NEW_PCONST (cfg, tramp_ins, trampoline);
4353         }
4354
4355         /* Set invoke_impl field */
4356         if (virtual_) {
4357                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), tramp_ins->dreg);
4358         } else {
4359                 dreg = alloc_preg (cfg);
4360                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, invoke_impl));
4361                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), dreg);
4362
4363                 dreg = alloc_preg (cfg);
4364                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, method_ptr));
4365                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), dreg);
4366         }
4367
4368         dreg = alloc_preg (cfg);
4369         MONO_EMIT_NEW_ICONST (cfg, dreg, virtual_ ? 1 : 0);
4370         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_is_virtual), dreg);
4371
4372         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
4373
4374         return obj;
4375 }
4376
4377 static MonoInst*
4378 handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
4379 {
4380         MonoJitICallInfo *info;
4381
4382         /* Need to register the icall so it gets an icall wrapper */
4383         info = mono_get_array_new_va_icall (rank);
4384
4385         cfg->flags |= MONO_CFG_HAS_VARARGS;
4386
4387         /* mono_array_new_va () needs a vararg calling convention */
4388         cfg->exception_message = g_strdup ("array-new");
4389         cfg->disable_llvm = TRUE;
4390
4391         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
4392         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
4393 }
4394
4395 /*
4396  * handle_constrained_gsharedvt_call:
4397  *
4398  *   Handle constrained calls where the receiver is a gsharedvt type.
4399  * Return the instruction representing the call. Set the cfg exception on failure.
4400  */
4401 static MonoInst*
4402 handle_constrained_gsharedvt_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp, MonoClass *constrained_class,
4403                                                                    gboolean *ref_emit_widen)
4404 {
4405         MonoInst *ins = NULL;
4406         gboolean emit_widen = *ref_emit_widen;
4407
4408         /*
4409          * Constrained calls need to behave differently at runtime dependending on whenever the receiver is instantiated as ref type or as a vtype.
4410          * 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
4411          * pack the arguments into an array, and do the rest of the work in in an icall.
4412          */
4413         if (((cmethod->klass == mono_defaults.object_class) || mono_class_is_interface (cmethod->klass) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) &&
4414                 (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)) &&
4415                 (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]))))) {
4416                 MonoInst *args [16];
4417
4418                 /*
4419                  * This case handles calls to
4420                  * - object:ToString()/Equals()/GetHashCode(),
4421                  * - System.IComparable<T>:CompareTo()
4422                  * - System.IEquatable<T>:Equals ()
4423                  * plus some simple interface calls enough to support AsyncTaskMethodBuilder.
4424                  */
4425
4426                 args [0] = sp [0];
4427                 if (mono_method_check_context_used (cmethod))
4428                         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cmethod), cmethod, MONO_RGCTX_INFO_METHOD);
4429                 else
4430                         EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
4431                 args [2] = mini_emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_class), constrained_class, MONO_RGCTX_INFO_KLASS);
4432
4433                 /* !fsig->hasthis is for the wrapper for the Object.GetType () icall */
4434                 if (fsig->hasthis && fsig->param_count) {
4435                         /* Pass the arguments using a localloc-ed array using the format expected by runtime_invoke () */
4436                         MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
4437                         ins->dreg = alloc_preg (cfg);
4438                         ins->inst_imm = fsig->param_count * sizeof (mgreg_t);
4439                         MONO_ADD_INS (cfg->cbb, ins);
4440                         args [4] = ins;
4441
4442                         if (mini_is_gsharedvt_type (fsig->params [0])) {
4443                                 int addr_reg, deref_arg_reg;
4444
4445                                 ins = emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4446                                 deref_arg_reg = alloc_preg (cfg);
4447                                 /* deref_arg = BOX_TYPE != MONO_GSHAREDVT_BOX_TYPE_VTYPE */
4448                                 EMIT_NEW_BIALU_IMM (cfg, args [3], OP_ISUB_IMM, deref_arg_reg, ins->dreg, 1);
4449
4450                                 EMIT_NEW_VARLOADA_VREG (cfg, ins, sp [1]->dreg, fsig->params [0]);
4451                                 addr_reg = ins->dreg;
4452                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, addr_reg);
4453                         } else {
4454                                 EMIT_NEW_ICONST (cfg, args [3], 0);
4455                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, sp [1]->dreg);
4456                         }
4457                 } else {
4458                         EMIT_NEW_ICONST (cfg, args [3], 0);
4459                         EMIT_NEW_ICONST (cfg, args [4], 0);
4460                 }
4461                 ins = mono_emit_jit_icall (cfg, mono_gsharedvt_constrained_call, args);
4462                 emit_widen = FALSE;
4463
4464                 if (mini_is_gsharedvt_type (fsig->ret)) {
4465                         ins = handle_unbox_gsharedvt (cfg, mono_class_from_mono_type (fsig->ret), ins);
4466                 } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret)) {
4467                         MonoInst *add;
4468
4469                         /* Unbox */
4470                         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), ins->dreg, sizeof (MonoObject));
4471                         MONO_ADD_INS (cfg->cbb, add);
4472                         /* Load value */
4473                         NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, add->dreg, 0);
4474                         MONO_ADD_INS (cfg->cbb, ins);
4475                         /* ins represents the call result */
4476                 }
4477         } else {
4478                 GSHAREDVT_FAILURE (CEE_CALLVIRT);
4479         }
4480
4481         *ref_emit_widen = emit_widen;
4482
4483         return ins;
4484
4485  exception_exit:
4486         return NULL;
4487 }
4488
4489 static void
4490 mono_emit_load_got_addr (MonoCompile *cfg)
4491 {
4492         MonoInst *getaddr, *dummy_use;
4493
4494         if (!cfg->got_var || cfg->got_var_allocated)
4495                 return;
4496
4497         MONO_INST_NEW (cfg, getaddr, OP_LOAD_GOTADDR);
4498         getaddr->cil_code = cfg->header->code;
4499         getaddr->dreg = cfg->got_var->dreg;
4500
4501         /* Add it to the start of the first bblock */
4502         if (cfg->bb_entry->code) {
4503                 getaddr->next = cfg->bb_entry->code;
4504                 cfg->bb_entry->code = getaddr;
4505         }
4506         else
4507                 MONO_ADD_INS (cfg->bb_entry, getaddr);
4508
4509         cfg->got_var_allocated = TRUE;
4510
4511         /* 
4512          * Add a dummy use to keep the got_var alive, since real uses might
4513          * only be generated by the back ends.
4514          * Add it to end_bblock, so the variable's lifetime covers the whole
4515          * method.
4516          * It would be better to make the usage of the got var explicit in all
4517          * cases when the backend needs it (i.e. calls, throw etc.), so this
4518          * wouldn't be needed.
4519          */
4520         NEW_DUMMY_USE (cfg, dummy_use, cfg->got_var);
4521         MONO_ADD_INS (cfg->bb_exit, dummy_use);
4522 }
4523
4524 static int inline_limit;
4525 static gboolean inline_limit_inited;
4526
4527 static gboolean
4528 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
4529 {
4530         MonoMethodHeaderSummary header;
4531         MonoVTable *vtable;
4532 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4533         MonoMethodSignature *sig = mono_method_signature (method);
4534         int i;
4535 #endif
4536
4537         if (cfg->disable_inline)
4538                 return FALSE;
4539         if (cfg->gsharedvt)
4540                 return FALSE;
4541
4542         if (cfg->inline_depth > 10)
4543                 return FALSE;
4544
4545         if (!mono_method_get_header_summary (method, &header))
4546                 return FALSE;
4547
4548         /*runtime, icall and pinvoke are checked by summary call*/
4549         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
4550             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
4551             (mono_class_is_marshalbyref (method->klass)) ||
4552             header.has_clauses)
4553                 return FALSE;
4554
4555         /* also consider num_locals? */
4556         /* Do the size check early to avoid creating vtables */
4557         if (!inline_limit_inited) {
4558                 if (g_getenv ("MONO_INLINELIMIT"))
4559                         inline_limit = atoi (g_getenv ("MONO_INLINELIMIT"));
4560                 else
4561                         inline_limit = INLINE_LENGTH_LIMIT;
4562                 inline_limit_inited = TRUE;
4563         }
4564         if (header.code_size >= inline_limit && !(method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
4565                 return FALSE;
4566
4567         /*
4568          * if we can initialize the class of the method right away, we do,
4569          * otherwise we don't allow inlining if the class needs initialization,
4570          * since it would mean inserting a call to mono_runtime_class_init()
4571          * inside the inlined code
4572          */
4573         if (cfg->gshared && method->klass->has_cctor && mini_class_check_context_used (cfg, method->klass))
4574                 return FALSE;
4575
4576         if (!(cfg->opt & MONO_OPT_SHARED)) {
4577                 /* The AggressiveInlining hint is a good excuse to force that cctor to run. */
4578                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING) {
4579                         if (method->klass->has_cctor) {
4580                                 vtable = mono_class_vtable (cfg->domain, method->klass);
4581                                 if (!vtable)
4582                                         return FALSE;
4583                                 if (!cfg->compile_aot) {
4584                                         MonoError error;
4585                                         if (!mono_runtime_class_init_full (vtable, &error)) {
4586                                                 mono_error_cleanup (&error);
4587                                                 return FALSE;
4588                                         }
4589                                 }
4590                         }
4591                 } else if (mono_class_is_before_field_init (method->klass)) {
4592                         if (cfg->run_cctors && method->klass->has_cctor) {
4593                                 /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
4594                                 if (!method->klass->runtime_info)
4595                                         /* No vtable created yet */
4596                                         return FALSE;
4597                                 vtable = mono_class_vtable (cfg->domain, method->klass);
4598                                 if (!vtable)
4599                                         return FALSE;
4600                                 /* This makes so that inline cannot trigger */
4601                                 /* .cctors: too many apps depend on them */
4602                                 /* running with a specific order... */
4603                                 if (! vtable->initialized)
4604                                         return FALSE;
4605                                 MonoError error;
4606                                 if (!mono_runtime_class_init_full (vtable, &error)) {
4607                                         mono_error_cleanup (&error);
4608                                         return FALSE;
4609                                 }
4610                         }
4611                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
4612                         if (!method->klass->runtime_info)
4613                                 /* No vtable created yet */
4614                                 return FALSE;
4615                         vtable = mono_class_vtable (cfg->domain, method->klass);
4616                         if (!vtable)
4617                                 return FALSE;
4618                         if (!vtable->initialized)
4619                                 return FALSE;
4620                 }
4621         } else {
4622                 /* 
4623                  * If we're compiling for shared code
4624                  * the cctor will need to be run at aot method load time, for example,
4625                  * or at the end of the compilation of the inlining method.
4626                  */
4627                 if (mono_class_needs_cctor_run (method->klass, NULL) && !mono_class_is_before_field_init (method->klass))
4628                         return FALSE;
4629         }
4630
4631 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4632         if (mono_arch_is_soft_float ()) {
4633                 /* FIXME: */
4634                 if (sig->ret && sig->ret->type == MONO_TYPE_R4)
4635                         return FALSE;
4636                 for (i = 0; i < sig->param_count; ++i)
4637                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
4638                                 return FALSE;
4639         }
4640 #endif
4641
4642         if (g_list_find (cfg->dont_inline, method))
4643                 return FALSE;
4644
4645         return TRUE;
4646 }
4647
4648 static gboolean
4649 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoClass *klass, MonoVTable *vtable)
4650 {
4651         if (!cfg->compile_aot) {
4652                 g_assert (vtable);
4653                 if (vtable->initialized)
4654                         return FALSE;
4655         }
4656
4657         if (mono_class_is_before_field_init (klass)) {
4658                 if (cfg->method == method)
4659                         return FALSE;
4660         }
4661
4662         if (!mono_class_needs_cctor_run (klass, method))
4663                 return FALSE;
4664
4665         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (klass == method->klass))
4666                 /* The initialization is already done before the method is called */
4667                 return FALSE;
4668
4669         return TRUE;
4670 }
4671
4672 MonoInst*
4673 mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
4674 {
4675         MonoInst *ins;
4676         guint32 size;
4677         int mult_reg, add_reg, array_reg, index_reg, index2_reg;
4678         int context_used;
4679
4680         if (mini_is_gsharedvt_variable_klass (klass)) {
4681                 size = -1;
4682         } else {
4683                 mono_class_init (klass);
4684                 size = mono_class_array_element_size (klass);
4685         }
4686
4687         mult_reg = alloc_preg (cfg);
4688         array_reg = arr->dreg;
4689         index_reg = index->dreg;
4690
4691 #if SIZEOF_REGISTER == 8
4692         /* The array reg is 64 bits but the index reg is only 32 */
4693         if (COMPILE_LLVM (cfg)) {
4694                 /* Not needed */
4695                 index2_reg = index_reg;
4696         } else {
4697                 index2_reg = alloc_preg (cfg);
4698                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
4699         }
4700 #else
4701         if (index->type == STACK_I8) {
4702                 index2_reg = alloc_preg (cfg);
4703                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I4, index2_reg, index_reg);
4704         } else {
4705                 index2_reg = index_reg;
4706         }
4707 #endif
4708
4709         if (bcheck)
4710                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
4711
4712 #if defined(TARGET_X86) || defined(TARGET_AMD64)
4713         if (size == 1 || size == 2 || size == 4 || size == 8) {
4714                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
4715
4716                 EMIT_NEW_X86_LEA (cfg, ins, array_reg, index2_reg, fast_log2 [size], MONO_STRUCT_OFFSET (MonoArray, vector));
4717                 ins->klass = mono_class_get_element_class (klass);
4718                 ins->type = STACK_MP;
4719
4720                 return ins;
4721         }
4722 #endif          
4723
4724         add_reg = alloc_ireg_mp (cfg);
4725
4726         if (size == -1) {
4727                 MonoInst *rgctx_ins;
4728
4729                 /* gsharedvt */
4730                 g_assert (cfg->gshared);
4731                 context_used = mini_class_check_context_used (cfg, klass);
4732                 g_assert (context_used);
4733                 rgctx_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE);
4734                 MONO_EMIT_NEW_BIALU (cfg, OP_IMUL, mult_reg, index2_reg, rgctx_ins->dreg);
4735         } else {
4736                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
4737         }
4738         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
4739         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
4740         ins->klass = mono_class_get_element_class (klass);
4741         ins->type = STACK_MP;
4742         MONO_ADD_INS (cfg->cbb, ins);
4743
4744         return ins;
4745 }
4746
4747 static MonoInst*
4748 mini_emit_ldelema_2_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index_ins1, MonoInst *index_ins2)
4749 {
4750         int bounds_reg = alloc_preg (cfg);
4751         int add_reg = alloc_ireg_mp (cfg);
4752         int mult_reg = alloc_preg (cfg);
4753         int mult2_reg = alloc_preg (cfg);
4754         int low1_reg = alloc_preg (cfg);
4755         int low2_reg = alloc_preg (cfg);
4756         int high1_reg = alloc_preg (cfg);
4757         int high2_reg = alloc_preg (cfg);
4758         int realidx1_reg = alloc_preg (cfg);
4759         int realidx2_reg = alloc_preg (cfg);
4760         int sum_reg = alloc_preg (cfg);
4761         int index1, index2, tmpreg;
4762         MonoInst *ins;
4763         guint32 size;
4764
4765         mono_class_init (klass);
4766         size = mono_class_array_element_size (klass);
4767
4768         index1 = index_ins1->dreg;
4769         index2 = index_ins2->dreg;
4770
4771 #if SIZEOF_REGISTER == 8
4772         /* The array reg is 64 bits but the index reg is only 32 */
4773         if (COMPILE_LLVM (cfg)) {
4774                 /* Not needed */
4775         } else {
4776                 tmpreg = alloc_preg (cfg);
4777                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index1);
4778                 index1 = tmpreg;
4779                 tmpreg = alloc_preg (cfg);
4780                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index2);
4781                 index2 = tmpreg;
4782         }
4783 #else
4784         // FIXME: Do we need to do something here for i8 indexes, like in ldelema_1_ins ?
4785         tmpreg = -1;
4786 #endif
4787
4788         /* range checking */
4789         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, 
4790                                        arr->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
4791
4792         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low1_reg, 
4793                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
4794         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx1_reg, index1, low1_reg);
4795         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high1_reg, 
4796                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
4797         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high1_reg, realidx1_reg);
4798         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
4799
4800         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low2_reg, 
4801                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
4802         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx2_reg, index2, low2_reg);
4803         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high2_reg, 
4804                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, length));
4805         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high2_reg, realidx2_reg);
4806         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
4807
4808         MONO_EMIT_NEW_BIALU (cfg, OP_PMUL, mult_reg, high2_reg, realidx1_reg);
4809         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, mult_reg, realidx2_reg);
4810         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PMUL_IMM, mult2_reg, sum_reg, size);
4811         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult2_reg, arr->dreg);
4812         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
4813
4814         ins->type = STACK_MP;
4815         ins->klass = klass;
4816         MONO_ADD_INS (cfg->cbb, ins);
4817
4818         return ins;
4819 }
4820
4821 static MonoInst*
4822 mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
4823 {
4824         int rank;
4825         MonoInst *addr;
4826         MonoMethod *addr_method;
4827         int element_size;
4828         MonoClass *eclass = cmethod->klass->element_class;
4829
4830         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
4831
4832         if (rank == 1)
4833                 return mini_emit_ldelema_1_ins (cfg, eclass, sp [0], sp [1], TRUE);
4834
4835         /* emit_ldelema_2 depends on OP_LMUL */
4836         if (!cfg->backend->emulate_mul_div && rank == 2 && (cfg->opt & MONO_OPT_INTRINS) && !mini_is_gsharedvt_variable_klass (eclass)) {
4837                 return mini_emit_ldelema_2_ins (cfg, eclass, sp [0], sp [1], sp [2]);
4838         }
4839
4840         if (mini_is_gsharedvt_variable_klass (eclass))
4841                 element_size = 0;
4842         else
4843                 element_size = mono_class_array_element_size (eclass);
4844         addr_method = mono_marshal_get_array_address (rank, element_size);
4845         addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
4846
4847         return addr;
4848 }
4849
4850 static MonoBreakPolicy
4851 always_insert_breakpoint (MonoMethod *method)
4852 {
4853         return MONO_BREAK_POLICY_ALWAYS;
4854 }
4855
4856 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
4857
4858 /**
4859  * mono_set_break_policy:
4860  * policy_callback: the new callback function
4861  *
4862  * Allow embedders to decide wherther to actually obey breakpoint instructions
4863  * (both break IL instructions and Debugger.Break () method calls), for example
4864  * to not allow an app to be aborted by a perfectly valid IL opcode when executing
4865  * untrusted or semi-trusted code.
4866  *
4867  * @policy_callback will be called every time a break point instruction needs to
4868  * be inserted with the method argument being the method that calls Debugger.Break()
4869  * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
4870  * if it wants the breakpoint to not be effective in the given method.
4871  * #MONO_BREAK_POLICY_ALWAYS is the default.
4872  */
4873 void
4874 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
4875 {
4876         if (policy_callback)
4877                 break_policy_func = policy_callback;
4878         else
4879                 break_policy_func = always_insert_breakpoint;
4880 }
4881
4882 static gboolean
4883 should_insert_brekpoint (MonoMethod *method) {
4884         switch (break_policy_func (method)) {
4885         case MONO_BREAK_POLICY_ALWAYS:
4886                 return TRUE;
4887         case MONO_BREAK_POLICY_NEVER:
4888                 return FALSE;
4889         case MONO_BREAK_POLICY_ON_DBG:
4890                 g_warning ("mdb no longer supported");
4891                 return FALSE;
4892         default:
4893                 g_warning ("Incorrect value returned from break policy callback");
4894                 return FALSE;
4895         }
4896 }
4897
4898 /* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
4899 static MonoInst*
4900 emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
4901 {
4902         MonoInst *addr, *store, *load;
4903         MonoClass *eklass = mono_class_from_mono_type (fsig->params [2]);
4904
4905         /* the bounds check is already done by the callers */
4906         addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
4907         if (is_set) {
4908                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
4909                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
4910                 if (mini_type_is_reference (&eklass->byval_arg))
4911                         emit_write_barrier (cfg, addr, load);
4912         } else {
4913                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
4914                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
4915         }
4916         return store;
4917 }
4918
4919
4920 static gboolean
4921 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
4922 {
4923         return mini_type_is_reference (&klass->byval_arg);
4924 }
4925
4926 static MonoInst*
4927 emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean safety_checks)
4928 {
4929         if (safety_checks && generic_class_is_reference_type (cfg, klass) &&
4930                 !(MONO_INS_IS_PCONST_NULL (sp [2]))) {
4931                 MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
4932                 MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
4933                 MonoInst *iargs [3];
4934
4935                 if (!helper->slot)
4936                         mono_class_setup_vtable (obj_array);
4937                 g_assert (helper->slot);
4938
4939                 if (sp [0]->type != STACK_OBJ)
4940                         return NULL;
4941                 if (sp [2]->type != STACK_OBJ)
4942                         return NULL;
4943
4944                 iargs [2] = sp [2];
4945                 iargs [1] = sp [1];
4946                 iargs [0] = sp [0];
4947
4948                 return mono_emit_method_call (cfg, helper, iargs, sp [0]);
4949         } else {
4950                 MonoInst *ins;
4951
4952                 if (mini_is_gsharedvt_variable_klass (klass)) {
4953                         MonoInst *addr;
4954
4955                         // FIXME-VT: OP_ICONST optimization
4956                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
4957                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
4958                         ins->opcode = OP_STOREV_MEMBASE;
4959                 } else if (sp [1]->opcode == OP_ICONST) {
4960                         int array_reg = sp [0]->dreg;
4961                         int index_reg = sp [1]->dreg;
4962                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
4963
4964                         if (SIZEOF_REGISTER == 8 && COMPILE_LLVM (cfg))
4965                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, index_reg);
4966
4967                         if (safety_checks)
4968                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
4969                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
4970                 } else {
4971                         MonoInst *addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], safety_checks);
4972                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
4973                         if (generic_class_is_reference_type (cfg, klass))
4974                                 emit_write_barrier (cfg, addr, sp [2]);
4975                 }
4976                 return ins;
4977         }
4978 }
4979
4980 static MonoInst*
4981 emit_array_unsafe_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
4982 {
4983         MonoClass *eklass;
4984         
4985         if (is_set)
4986                 eklass = mono_class_from_mono_type (fsig->params [2]);
4987         else
4988                 eklass = mono_class_from_mono_type (fsig->ret);
4989
4990         if (is_set) {
4991                 return emit_array_store (cfg, eklass, args, FALSE);
4992         } else {
4993                 MonoInst *ins, *addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
4994                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &eklass->byval_arg, addr->dreg, 0);
4995                 return ins;
4996         }
4997 }
4998
4999 static gboolean
5000 is_unsafe_mov_compatible (MonoCompile *cfg, MonoClass *param_klass, MonoClass *return_klass)
5001 {
5002         uint32_t align;
5003         int param_size, return_size;
5004
5005         param_klass = mono_class_from_mono_type (mini_get_underlying_type (&param_klass->byval_arg));
5006         return_klass = mono_class_from_mono_type (mini_get_underlying_type (&return_klass->byval_arg));
5007
5008         if (cfg->verbose_level > 3)
5009                 printf ("[UNSAFE-MOV-INTRISIC] %s <- %s\n", return_klass->name, param_klass->name);
5010
5011         //Don't allow mixing reference types with value types
5012         if (param_klass->valuetype != return_klass->valuetype) {
5013                 if (cfg->verbose_level > 3)
5014                         printf ("[UNSAFE-MOV-INTRISIC]\tone of the args is a valuetype and the other is not\n");
5015                 return FALSE;
5016         }
5017
5018         if (!param_klass->valuetype) {
5019                 if (cfg->verbose_level > 3)
5020                         printf ("[UNSAFE-MOV-INTRISIC]\targs are reference types\n");
5021                 return TRUE;
5022         }
5023
5024         //That are blitable
5025         if (param_klass->has_references || return_klass->has_references)
5026                 return FALSE;
5027
5028         /* Avoid mixing structs and primitive types/enums, they need to be handled differently in the JIT */
5029         if ((MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && !MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)) ||
5030                 (!MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && MONO_TYPE_ISSTRUCT (&return_klass->byval_arg))) {
5031                         if (cfg->verbose_level > 3)
5032                                 printf ("[UNSAFE-MOV-INTRISIC]\tmixing structs and scalars\n");
5033                 return FALSE;
5034         }
5035
5036         if (param_klass->byval_arg.type == MONO_TYPE_R4 || param_klass->byval_arg.type == MONO_TYPE_R8 ||
5037                 return_klass->byval_arg.type == MONO_TYPE_R4 || return_klass->byval_arg.type == MONO_TYPE_R8) {
5038                 if (cfg->verbose_level > 3)
5039                         printf ("[UNSAFE-MOV-INTRISIC]\tfloat or double are not supported\n");
5040                 return FALSE;
5041         }
5042
5043         param_size = mono_class_value_size (param_klass, &align);
5044         return_size = mono_class_value_size (return_klass, &align);
5045
5046         //We can do it if sizes match
5047         if (param_size == return_size) {
5048                 if (cfg->verbose_level > 3)
5049                         printf ("[UNSAFE-MOV-INTRISIC]\tsame size\n");
5050                 return TRUE;
5051         }
5052
5053         //No simple way to handle struct if sizes don't match
5054         if (MONO_TYPE_ISSTRUCT (&param_klass->byval_arg)) {
5055                 if (cfg->verbose_level > 3)
5056                         printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch and type is a struct\n");
5057                 return FALSE;
5058         }
5059
5060         /*
5061          * Same reg size category.
5062          * A quick note on why we don't require widening here.
5063          * The intrinsic is "R Array.UnsafeMov<S,R> (S s)".
5064          *
5065          * Since the source value comes from a function argument, the JIT will already have
5066          * the value in a VREG and performed any widening needed before (say, when loading from a field).
5067          */
5068         if (param_size <= 4 && return_size <= 4) {
5069                 if (cfg->verbose_level > 3)
5070                         printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch but both are of the same reg class\n");
5071                 return TRUE;
5072         }
5073
5074         return FALSE;
5075 }
5076
5077 static MonoInst*
5078 emit_array_unsafe_mov (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args)
5079 {
5080         MonoClass *param_klass = mono_class_from_mono_type (fsig->params [0]);
5081         MonoClass *return_klass = mono_class_from_mono_type (fsig->ret);
5082
5083         if (mini_is_gsharedvt_variable_type (fsig->ret))
5084                 return NULL;
5085
5086         //Valuetypes that are semantically equivalent or numbers than can be widened to
5087         if (is_unsafe_mov_compatible (cfg, param_klass, return_klass))
5088                 return args [0];
5089
5090         //Arrays of valuetypes that are semantically equivalent
5091         if (param_klass->rank == 1 && return_klass->rank == 1 && is_unsafe_mov_compatible (cfg, param_klass->element_class, return_klass->element_class))
5092                 return args [0];
5093
5094         return NULL;
5095 }
5096
5097 static MonoInst*
5098 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5099 {
5100 #ifdef MONO_ARCH_SIMD_INTRINSICS
5101         MonoInst *ins = NULL;
5102
5103         if (cfg->opt & MONO_OPT_SIMD) {
5104                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5105                 if (ins)
5106                         return ins;
5107         }
5108 #endif
5109
5110         return mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5111 }
5112
5113 static MonoInst*
5114 emit_memory_barrier (MonoCompile *cfg, int kind)
5115 {
5116         MonoInst *ins = NULL;
5117         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
5118         MONO_ADD_INS (cfg->cbb, ins);
5119         ins->backend.memory_barrier_kind = kind;
5120
5121         return ins;
5122 }
5123
5124 static MonoInst*
5125 llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5126 {
5127         MonoInst *ins = NULL;
5128         int opcode = 0;
5129
5130         /* The LLVM backend supports these intrinsics */
5131         if (cmethod->klass == mono_defaults.math_class) {
5132                 if (strcmp (cmethod->name, "Sin") == 0) {
5133                         opcode = OP_SIN;
5134                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5135                         opcode = OP_COS;
5136                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
5137                         opcode = OP_SQRT;
5138                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5139                         opcode = OP_ABS;
5140                 }
5141
5142                 if (opcode && fsig->param_count == 1) {
5143                         MONO_INST_NEW (cfg, ins, opcode);
5144                         ins->type = STACK_R8;
5145                         ins->dreg = mono_alloc_dreg (cfg, ins->type);
5146                         ins->sreg1 = args [0]->dreg;
5147                         MONO_ADD_INS (cfg->cbb, ins);
5148                 }
5149
5150                 opcode = 0;
5151                 if (cfg->opt & MONO_OPT_CMOV) {
5152                         if (strcmp (cmethod->name, "Min") == 0) {
5153                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5154                                         opcode = OP_IMIN;
5155                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5156                                         opcode = OP_IMIN_UN;
5157                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5158                                         opcode = OP_LMIN;
5159                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5160                                         opcode = OP_LMIN_UN;
5161                         } else if (strcmp (cmethod->name, "Max") == 0) {
5162                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5163                                         opcode = OP_IMAX;
5164                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5165                                         opcode = OP_IMAX_UN;
5166                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5167                                         opcode = OP_LMAX;
5168                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5169                                         opcode = OP_LMAX_UN;
5170                         }
5171                 }
5172
5173                 if (opcode && fsig->param_count == 2) {
5174                         MONO_INST_NEW (cfg, ins, opcode);
5175                         ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
5176                         ins->dreg = mono_alloc_dreg (cfg, ins->type);
5177                         ins->sreg1 = args [0]->dreg;
5178                         ins->sreg2 = args [1]->dreg;
5179                         MONO_ADD_INS (cfg->cbb, ins);
5180                 }
5181         }
5182
5183         return ins;
5184 }
5185
5186 static MonoInst*
5187 mini_emit_inst_for_sharable_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5188 {
5189         if (cmethod->klass == mono_defaults.array_class) {
5190                 if (strcmp (cmethod->name, "UnsafeStore") == 0)
5191                         return emit_array_unsafe_access (cfg, fsig, args, TRUE);
5192                 else if (strcmp (cmethod->name, "UnsafeLoad") == 0)
5193                         return emit_array_unsafe_access (cfg, fsig, args, FALSE);
5194                 else if (strcmp (cmethod->name, "UnsafeMov") == 0)
5195                         return emit_array_unsafe_mov (cfg, fsig, args);
5196         }
5197
5198         return NULL;
5199 }
5200
5201 static MonoInst*
5202 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5203 {
5204         MonoInst *ins = NULL;
5205
5206          MonoClass *runtime_helpers_class = mono_class_get_runtime_helpers_class ();
5207
5208         if (cmethod->klass == mono_defaults.string_class) {
5209                 if (strcmp (cmethod->name, "get_Chars") == 0 && fsig->param_count + fsig->hasthis == 2) {
5210                         int dreg = alloc_ireg (cfg);
5211                         int index_reg = alloc_preg (cfg);
5212                         int add_reg = alloc_preg (cfg);
5213
5214 #if SIZEOF_REGISTER == 8
5215                         if (COMPILE_LLVM (cfg)) {
5216                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, args [1]->dreg);
5217                         } else {
5218                                 /* The array reg is 64 bits but the index reg is only 32 */
5219                                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
5220                         }
5221 #else
5222                         index_reg = args [1]->dreg;
5223 #endif  
5224                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
5225
5226 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5227                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, MONO_STRUCT_OFFSET (MonoString, chars));
5228                         add_reg = ins->dreg;
5229                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5230                                                                    add_reg, 0);
5231 #else
5232                         int mult_reg = alloc_preg (cfg);
5233                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
5234                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5235                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5236                                                                    add_reg, MONO_STRUCT_OFFSET (MonoString, chars));
5237 #endif
5238                         type_from_op (cfg, ins, NULL, NULL);
5239                         return ins;
5240                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
5241                         int dreg = alloc_ireg (cfg);
5242                         /* Decompose later to allow more optimizations */
5243                         EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
5244                         ins->type = STACK_I4;
5245                         ins->flags |= MONO_INST_FAULT;
5246                         cfg->cbb->has_array_access = TRUE;
5247                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
5248
5249                         return ins;
5250                 } else 
5251                         return NULL;
5252         } else if (cmethod->klass == mono_defaults.object_class) {
5253                 if (strcmp (cmethod->name, "GetType") == 0 && fsig->param_count + fsig->hasthis == 1) {
5254                         int dreg = alloc_ireg_ref (cfg);
5255                         int vt_reg = alloc_preg (cfg);
5256                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5257                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, MONO_STRUCT_OFFSET (MonoVTable, type));
5258                         type_from_op (cfg, ins, NULL, NULL);
5259
5260                         return ins;
5261                 } else if (!cfg->backend->emulate_mul_div && strcmp (cmethod->name, "InternalGetHashCode") == 0 && fsig->param_count == 1 && !mono_gc_is_moving ()) {
5262                         int dreg = alloc_ireg (cfg);
5263                         int t1 = alloc_ireg (cfg);
5264         
5265                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
5266                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
5267                         ins->type = STACK_I4;
5268
5269                         return ins;
5270                 } else if (strcmp (cmethod->name, ".ctor") == 0 && fsig->param_count == 0) {
5271                         MONO_INST_NEW (cfg, ins, OP_NOP);
5272                         MONO_ADD_INS (cfg->cbb, ins);
5273                         return ins;
5274                 } else
5275                         return NULL;
5276         } else if (cmethod->klass == mono_defaults.array_class) {
5277                 if (strcmp (cmethod->name, "GetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
5278                         return emit_array_generic_access (cfg, fsig, args, FALSE);
5279                 else if (strcmp (cmethod->name, "SetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
5280                         return emit_array_generic_access (cfg, fsig, args, TRUE);
5281
5282 #ifndef MONO_BIG_ARRAYS
5283                 /*
5284                  * This is an inline version of GetLength/GetLowerBound(0) used frequently in
5285                  * Array methods.
5286                  */
5287                 else if (((strcmp (cmethod->name, "GetLength") == 0 && fsig->param_count + fsig->hasthis == 2) ||
5288                          (strcmp (cmethod->name, "GetLowerBound") == 0 && fsig->param_count + fsig->hasthis == 2)) &&
5289                          args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) {
5290                         int dreg = alloc_ireg (cfg);
5291                         int bounds_reg = alloc_ireg_mp (cfg);
5292                         MonoBasicBlock *end_bb, *szarray_bb;
5293                         gboolean get_length = strcmp (cmethod->name, "GetLength") == 0;
5294
5295                         NEW_BBLOCK (cfg, end_bb);
5296                         NEW_BBLOCK (cfg, szarray_bb);
5297
5298                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOAD_MEMBASE, bounds_reg,
5299                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5300                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
5301                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, szarray_bb);
5302                         /* Non-szarray case */
5303                         if (get_length)
5304                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5305                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5306                         else
5307                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5308                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5309                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
5310                         MONO_START_BB (cfg, szarray_bb);
5311                         /* Szarray case */
5312                         if (get_length)
5313                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5314                                                                            args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
5315                         else
5316                                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
5317                         MONO_START_BB (cfg, end_bb);
5318
5319                         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg);
5320                         ins->type = STACK_I4;
5321                         
5322                         return ins;
5323                 }
5324 #endif
5325
5326                 if (cmethod->name [0] != 'g')
5327                         return NULL;
5328
5329                 if (strcmp (cmethod->name, "get_Rank") == 0 && fsig->param_count + fsig->hasthis == 1) {
5330                         int dreg = alloc_ireg (cfg);
5331                         int vtable_reg = alloc_preg (cfg);
5332                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
5333                                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5334                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
5335                                                                    vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
5336                         type_from_op (cfg, ins, NULL, NULL);
5337
5338                         return ins;
5339                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
5340                         int dreg = alloc_ireg (cfg);
5341
5342                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
5343                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
5344                         type_from_op (cfg, ins, NULL, NULL);
5345
5346                         return ins;
5347                 } else
5348                         return NULL;
5349         } else if (cmethod->klass == runtime_helpers_class) {
5350                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0 && fsig->param_count == 0) {
5351                         EMIT_NEW_ICONST (cfg, ins, MONO_STRUCT_OFFSET (MonoString, chars));
5352                         return ins;
5353                 } else
5354                         return NULL;
5355         } else if (cmethod->klass == mono_defaults.monitor_class) {
5356                 gboolean is_enter = FALSE;
5357                 gboolean is_v4 = FALSE;
5358
5359                 if (!strcmp (cmethod->name, "Enter") && fsig->param_count == 2 && fsig->params [1]->byref) {
5360                         is_enter = TRUE;
5361                         is_v4 = TRUE;
5362                 }
5363                 if (!strcmp (cmethod->name, "Enter") && fsig->param_count == 1)
5364                         is_enter = TRUE;
5365
5366                 if (is_enter) {
5367                         /*
5368                          * To make async stack traces work, icalls which can block should have a wrapper.
5369                          * For Monitor.Enter, emit two calls: a fastpath which doesn't have a wrapper, and a slowpath, which does.
5370                          */
5371                         MonoBasicBlock *end_bb;
5372
5373                         NEW_BBLOCK (cfg, end_bb);
5374
5375                         ins = mono_emit_jit_icall (cfg, is_v4 ? (gpointer)mono_monitor_enter_v4_fast : (gpointer)mono_monitor_enter_fast, args);
5376                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, ins->dreg, 0);
5377                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, end_bb);
5378                         ins = mono_emit_jit_icall (cfg, is_v4 ? (gpointer)mono_monitor_enter_v4 : (gpointer)mono_monitor_enter, args);
5379                         MONO_START_BB (cfg, end_bb);
5380                         return ins;
5381                 }
5382         } else if (cmethod->klass == mono_defaults.thread_class) {
5383                 if (strcmp (cmethod->name, "SpinWait_nop") == 0 && fsig->param_count == 0) {
5384                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
5385                         MONO_ADD_INS (cfg->cbb, ins);
5386                         return ins;
5387                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0) {
5388                         return emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5389                 } else if (!strcmp (cmethod->name, "VolatileRead") && fsig->param_count == 1) {
5390                         guint32 opcode = 0;
5391                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
5392
5393                         if (fsig->params [0]->type == MONO_TYPE_I1)
5394                                 opcode = OP_LOADI1_MEMBASE;
5395                         else if (fsig->params [0]->type == MONO_TYPE_U1)
5396                                 opcode = OP_LOADU1_MEMBASE;
5397                         else if (fsig->params [0]->type == MONO_TYPE_I2)
5398                                 opcode = OP_LOADI2_MEMBASE;
5399                         else if (fsig->params [0]->type == MONO_TYPE_U2)
5400                                 opcode = OP_LOADU2_MEMBASE;
5401                         else if (fsig->params [0]->type == MONO_TYPE_I4)
5402                                 opcode = OP_LOADI4_MEMBASE;
5403                         else if (fsig->params [0]->type == MONO_TYPE_U4)
5404                                 opcode = OP_LOADU4_MEMBASE;
5405                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
5406                                 opcode = OP_LOADI8_MEMBASE;
5407                         else if (fsig->params [0]->type == MONO_TYPE_R4)
5408                                 opcode = OP_LOADR4_MEMBASE;
5409                         else if (fsig->params [0]->type == MONO_TYPE_R8)
5410                                 opcode = OP_LOADR8_MEMBASE;
5411                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
5412                                 opcode = OP_LOAD_MEMBASE;
5413
5414                         if (opcode) {
5415                                 MONO_INST_NEW (cfg, ins, opcode);
5416                                 ins->inst_basereg = args [0]->dreg;
5417                                 ins->inst_offset = 0;
5418                                 MONO_ADD_INS (cfg->cbb, ins);
5419
5420                                 switch (fsig->params [0]->type) {
5421                                 case MONO_TYPE_I1:
5422                                 case MONO_TYPE_U1:
5423                                 case MONO_TYPE_I2:
5424                                 case MONO_TYPE_U2:
5425                                 case MONO_TYPE_I4:
5426                                 case MONO_TYPE_U4:
5427                                         ins->dreg = mono_alloc_ireg (cfg);
5428                                         ins->type = STACK_I4;
5429                                         break;
5430                                 case MONO_TYPE_I8:
5431                                 case MONO_TYPE_U8:
5432                                         ins->dreg = mono_alloc_lreg (cfg);
5433                                         ins->type = STACK_I8;
5434                                         break;
5435                                 case MONO_TYPE_I:
5436                                 case MONO_TYPE_U:
5437                                         ins->dreg = mono_alloc_ireg (cfg);
5438 #if SIZEOF_REGISTER == 8
5439                                         ins->type = STACK_I8;
5440 #else
5441                                         ins->type = STACK_I4;
5442 #endif
5443                                         break;
5444                                 case MONO_TYPE_R4:
5445                                 case MONO_TYPE_R8:
5446                                         ins->dreg = mono_alloc_freg (cfg);
5447                                         ins->type = STACK_R8;
5448                                         break;
5449                                 default:
5450                                         g_assert (mini_type_is_reference (fsig->params [0]));
5451                                         ins->dreg = mono_alloc_ireg_ref (cfg);
5452                                         ins->type = STACK_OBJ;
5453                                         break;
5454                                 }
5455
5456                                 if (opcode == OP_LOADI8_MEMBASE)
5457                                         ins = mono_decompose_opcode (cfg, ins);
5458
5459                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5460
5461                                 return ins;
5462                         }
5463                 } else if (!strcmp (cmethod->name, "VolatileWrite") && fsig->param_count == 2) {
5464                         guint32 opcode = 0;
5465                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
5466
5467                         if (fsig->params [0]->type == MONO_TYPE_I1 || fsig->params [0]->type == MONO_TYPE_U1)
5468                                 opcode = OP_STOREI1_MEMBASE_REG;
5469                         else if (fsig->params [0]->type == MONO_TYPE_I2 || fsig->params [0]->type == MONO_TYPE_U2)
5470                                 opcode = OP_STOREI2_MEMBASE_REG;
5471                         else if (fsig->params [0]->type == MONO_TYPE_I4 || fsig->params [0]->type == MONO_TYPE_U4)
5472                                 opcode = OP_STOREI4_MEMBASE_REG;
5473                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
5474                                 opcode = OP_STOREI8_MEMBASE_REG;
5475                         else if (fsig->params [0]->type == MONO_TYPE_R4)
5476                                 opcode = OP_STORER4_MEMBASE_REG;
5477                         else if (fsig->params [0]->type == MONO_TYPE_R8)
5478                                 opcode = OP_STORER8_MEMBASE_REG;
5479                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
5480                                 opcode = OP_STORE_MEMBASE_REG;
5481
5482                         if (opcode) {
5483                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5484
5485                                 MONO_INST_NEW (cfg, ins, opcode);
5486                                 ins->sreg1 = args [1]->dreg;
5487                                 ins->inst_destbasereg = args [0]->dreg;
5488                                 ins->inst_offset = 0;
5489                                 MONO_ADD_INS (cfg->cbb, ins);
5490
5491                                 if (opcode == OP_STOREI8_MEMBASE_REG)
5492                                         ins = mono_decompose_opcode (cfg, ins);
5493
5494                                 return ins;
5495                         }
5496                 }
5497         } else if (cmethod->klass->image == mono_defaults.corlib &&
5498                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
5499                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
5500                 ins = NULL;
5501
5502 #if SIZEOF_REGISTER == 8
5503                 if (!cfg->llvm_only && strcmp (cmethod->name, "Read") == 0 && fsig->param_count == 1 && (fsig->params [0]->type == MONO_TYPE_I8)) {
5504                         if (!cfg->llvm_only && mono_arch_opcode_supported (OP_ATOMIC_LOAD_I8)) {
5505                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_LOAD_I8);
5506                                 ins->dreg = mono_alloc_preg (cfg);
5507                                 ins->sreg1 = args [0]->dreg;
5508                                 ins->type = STACK_I8;
5509                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_SEQ;
5510                                 MONO_ADD_INS (cfg->cbb, ins);
5511                         } else {
5512                                 MonoInst *load_ins;
5513
5514                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5515
5516                                 /* 64 bit reads are already atomic */
5517                                 MONO_INST_NEW (cfg, load_ins, OP_LOADI8_MEMBASE);
5518                                 load_ins->dreg = mono_alloc_preg (cfg);
5519                                 load_ins->inst_basereg = args [0]->dreg;
5520                                 load_ins->inst_offset = 0;
5521                                 load_ins->type = STACK_I8;
5522                                 MONO_ADD_INS (cfg->cbb, load_ins);
5523
5524                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5525
5526                                 ins = load_ins;
5527                         }
5528                 }
5529 #endif
5530
5531                 if (strcmp (cmethod->name, "Increment") == 0 && fsig->param_count == 1) {
5532                         MonoInst *ins_iconst;
5533                         guint32 opcode = 0;
5534
5535                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5536                                 opcode = OP_ATOMIC_ADD_I4;
5537                                 cfg->has_atomic_add_i4 = TRUE;
5538                         }
5539 #if SIZEOF_REGISTER == 8
5540                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5541                                 opcode = OP_ATOMIC_ADD_I8;
5542 #endif
5543                         if (opcode) {
5544                                 if (!mono_arch_opcode_supported (opcode))
5545                                         return NULL;
5546                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
5547                                 ins_iconst->inst_c0 = 1;
5548                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
5549                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
5550
5551                                 MONO_INST_NEW (cfg, ins, opcode);
5552                                 ins->dreg = mono_alloc_ireg (cfg);
5553                                 ins->inst_basereg = args [0]->dreg;
5554                                 ins->inst_offset = 0;
5555                                 ins->sreg2 = ins_iconst->dreg;
5556                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
5557                                 MONO_ADD_INS (cfg->cbb, ins);
5558                         }
5559                 } else if (strcmp (cmethod->name, "Decrement") == 0 && fsig->param_count == 1) {
5560                         MonoInst *ins_iconst;
5561                         guint32 opcode = 0;
5562
5563                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5564                                 opcode = OP_ATOMIC_ADD_I4;
5565                                 cfg->has_atomic_add_i4 = TRUE;
5566                         }
5567 #if SIZEOF_REGISTER == 8
5568                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5569                                 opcode = OP_ATOMIC_ADD_I8;
5570 #endif
5571                         if (opcode) {
5572                                 if (!mono_arch_opcode_supported (opcode))
5573                                         return NULL;
5574                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
5575                                 ins_iconst->inst_c0 = -1;
5576                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
5577                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
5578
5579                                 MONO_INST_NEW (cfg, ins, opcode);
5580                                 ins->dreg = mono_alloc_ireg (cfg);
5581                                 ins->inst_basereg = args [0]->dreg;
5582                                 ins->inst_offset = 0;
5583                                 ins->sreg2 = ins_iconst->dreg;
5584                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
5585                                 MONO_ADD_INS (cfg->cbb, ins);
5586                         }
5587                 } else if (strcmp (cmethod->name, "Add") == 0 && fsig->param_count == 2) {
5588                         guint32 opcode = 0;
5589
5590                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5591                                 opcode = OP_ATOMIC_ADD_I4;
5592                                 cfg->has_atomic_add_i4 = TRUE;
5593                         }
5594 #if SIZEOF_REGISTER == 8
5595                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5596                                 opcode = OP_ATOMIC_ADD_I8;
5597 #endif
5598                         if (opcode) {
5599                                 if (!mono_arch_opcode_supported (opcode))
5600                                         return NULL;
5601                                 MONO_INST_NEW (cfg, ins, opcode);
5602                                 ins->dreg = mono_alloc_ireg (cfg);
5603                                 ins->inst_basereg = args [0]->dreg;
5604                                 ins->inst_offset = 0;
5605                                 ins->sreg2 = args [1]->dreg;
5606                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
5607                                 MONO_ADD_INS (cfg->cbb, ins);
5608                         }
5609                 }
5610                 else if (strcmp (cmethod->name, "Exchange") == 0 && fsig->param_count == 2) {
5611                         MonoInst *f2i = NULL, *i2f;
5612                         guint32 opcode, f2i_opcode, i2f_opcode;
5613                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
5614                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
5615
5616                         if (fsig->params [0]->type == MONO_TYPE_I4 ||
5617                             fsig->params [0]->type == MONO_TYPE_R4) {
5618                                 opcode = OP_ATOMIC_EXCHANGE_I4;
5619                                 f2i_opcode = OP_MOVE_F_TO_I4;
5620                                 i2f_opcode = OP_MOVE_I4_TO_F;
5621                                 cfg->has_atomic_exchange_i4 = TRUE;
5622                         }
5623 #if SIZEOF_REGISTER == 8
5624                         else if (is_ref ||
5625                                  fsig->params [0]->type == MONO_TYPE_I8 ||
5626                                  fsig->params [0]->type == MONO_TYPE_R8 ||
5627                                  fsig->params [0]->type == MONO_TYPE_I) {
5628                                 opcode = OP_ATOMIC_EXCHANGE_I8;
5629                                 f2i_opcode = OP_MOVE_F_TO_I8;
5630                                 i2f_opcode = OP_MOVE_I8_TO_F;
5631                         }
5632 #else
5633                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I) {
5634                                 opcode = OP_ATOMIC_EXCHANGE_I4;
5635                                 cfg->has_atomic_exchange_i4 = TRUE;
5636                         }
5637 #endif
5638                         else
5639                                 return NULL;
5640
5641                         if (!mono_arch_opcode_supported (opcode))
5642                                 return NULL;
5643
5644                         if (is_float) {
5645                                 /* TODO: Decompose these opcodes instead of bailing here. */
5646                                 if (COMPILE_SOFT_FLOAT (cfg))
5647                                         return NULL;
5648
5649                                 MONO_INST_NEW (cfg, f2i, f2i_opcode);
5650                                 f2i->dreg = mono_alloc_ireg (cfg);
5651                                 f2i->sreg1 = args [1]->dreg;
5652                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
5653                                         f2i->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
5654                                 MONO_ADD_INS (cfg->cbb, f2i);
5655                         }
5656
5657                         MONO_INST_NEW (cfg, ins, opcode);
5658                         ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg);
5659                         ins->inst_basereg = args [0]->dreg;
5660                         ins->inst_offset = 0;
5661                         ins->sreg2 = is_float ? f2i->dreg : args [1]->dreg;
5662                         MONO_ADD_INS (cfg->cbb, ins);
5663
5664                         switch (fsig->params [0]->type) {
5665                         case MONO_TYPE_I4:
5666                                 ins->type = STACK_I4;
5667                                 break;
5668                         case MONO_TYPE_I8:
5669                                 ins->type = STACK_I8;
5670                                 break;
5671                         case MONO_TYPE_I:
5672 #if SIZEOF_REGISTER == 8
5673                                 ins->type = STACK_I8;
5674 #else
5675                                 ins->type = STACK_I4;
5676 #endif
5677                                 break;
5678                         case MONO_TYPE_R4:
5679                         case MONO_TYPE_R8:
5680                                 ins->type = STACK_R8;
5681                                 break;
5682                         default:
5683                                 g_assert (mini_type_is_reference (fsig->params [0]));
5684                                 ins->type = STACK_OBJ;
5685                                 break;
5686                         }
5687
5688                         if (is_float) {
5689                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
5690                                 i2f->dreg = mono_alloc_freg (cfg);
5691                                 i2f->sreg1 = ins->dreg;
5692                                 i2f->type = STACK_R8;
5693                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
5694                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
5695                                 MONO_ADD_INS (cfg->cbb, i2f);
5696
5697                                 ins = i2f;
5698                         }
5699
5700                         if (cfg->gen_write_barriers && is_ref)
5701                                 emit_write_barrier (cfg, args [0], args [1]);
5702                 }
5703                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 3) {
5704                         MonoInst *f2i_new = NULL, *f2i_cmp = NULL, *i2f;
5705                         guint32 opcode, f2i_opcode, i2f_opcode;
5706                         gboolean is_ref = mini_type_is_reference (fsig->params [1]);
5707                         gboolean is_float = fsig->params [1]->type == MONO_TYPE_R4 || fsig->params [1]->type == MONO_TYPE_R8;
5708
5709                         if (fsig->params [1]->type == MONO_TYPE_I4 ||
5710                             fsig->params [1]->type == MONO_TYPE_R4) {
5711                                 opcode = OP_ATOMIC_CAS_I4;
5712                                 f2i_opcode = OP_MOVE_F_TO_I4;
5713                                 i2f_opcode = OP_MOVE_I4_TO_F;
5714                                 cfg->has_atomic_cas_i4 = TRUE;
5715                         }
5716 #if SIZEOF_REGISTER == 8
5717                         else if (is_ref ||
5718                                  fsig->params [1]->type == MONO_TYPE_I8 ||
5719                                  fsig->params [1]->type == MONO_TYPE_R8 ||
5720                                  fsig->params [1]->type == MONO_TYPE_I) {
5721                                 opcode = OP_ATOMIC_CAS_I8;
5722                                 f2i_opcode = OP_MOVE_F_TO_I8;
5723                                 i2f_opcode = OP_MOVE_I8_TO_F;
5724                         }
5725 #else
5726                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I) {
5727                                 opcode = OP_ATOMIC_CAS_I4;
5728                                 cfg->has_atomic_cas_i4 = TRUE;
5729                         }
5730 #endif
5731                         else
5732                                 return NULL;
5733
5734                         if (!mono_arch_opcode_supported (opcode))
5735                                 return NULL;
5736
5737                         if (is_float) {
5738                                 /* TODO: Decompose these opcodes instead of bailing here. */
5739                                 if (COMPILE_SOFT_FLOAT (cfg))
5740                                         return NULL;
5741
5742                                 MONO_INST_NEW (cfg, f2i_new, f2i_opcode);
5743                                 f2i_new->dreg = mono_alloc_ireg (cfg);
5744                                 f2i_new->sreg1 = args [1]->dreg;
5745                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
5746                                         f2i_new->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
5747                                 MONO_ADD_INS (cfg->cbb, f2i_new);
5748
5749                                 MONO_INST_NEW (cfg, f2i_cmp, f2i_opcode);
5750                                 f2i_cmp->dreg = mono_alloc_ireg (cfg);
5751                                 f2i_cmp->sreg1 = args [2]->dreg;
5752                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
5753                                         f2i_cmp->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
5754                                 MONO_ADD_INS (cfg->cbb, f2i_cmp);
5755                         }
5756
5757                         MONO_INST_NEW (cfg, ins, opcode);
5758                         ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
5759                         ins->sreg1 = args [0]->dreg;
5760                         ins->sreg2 = is_float ? f2i_new->dreg : args [1]->dreg;
5761                         ins->sreg3 = is_float ? f2i_cmp->dreg : args [2]->dreg;
5762                         MONO_ADD_INS (cfg->cbb, ins);
5763
5764                         switch (fsig->params [1]->type) {
5765                         case MONO_TYPE_I4:
5766                                 ins->type = STACK_I4;
5767                                 break;
5768                         case MONO_TYPE_I8:
5769                                 ins->type = STACK_I8;
5770                                 break;
5771                         case MONO_TYPE_I:
5772 #if SIZEOF_REGISTER == 8
5773                                 ins->type = STACK_I8;
5774 #else
5775                                 ins->type = STACK_I4;
5776 #endif
5777                                 break;
5778                         case MONO_TYPE_R4:
5779                                 ins->type = cfg->r4_stack_type;
5780                                 break;
5781                         case MONO_TYPE_R8:
5782                                 ins->type = STACK_R8;
5783                                 break;
5784                         default:
5785                                 g_assert (mini_type_is_reference (fsig->params [1]));
5786                                 ins->type = STACK_OBJ;
5787                                 break;
5788                         }
5789
5790                         if (is_float) {
5791                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
5792                                 i2f->dreg = mono_alloc_freg (cfg);
5793                                 i2f->sreg1 = ins->dreg;
5794                                 i2f->type = STACK_R8;
5795                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
5796                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
5797                                 MONO_ADD_INS (cfg->cbb, i2f);
5798
5799                                 ins = i2f;
5800                         }
5801
5802                         if (cfg->gen_write_barriers && is_ref)
5803                                 emit_write_barrier (cfg, args [0], args [1]);
5804                 }
5805                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 4 &&
5806                          fsig->params [1]->type == MONO_TYPE_I4) {
5807                         MonoInst *cmp, *ceq;
5808
5809                         if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I4))
5810                                 return NULL;
5811
5812                         /* int32 r = CAS (location, value, comparand); */
5813                         MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
5814                         ins->dreg = alloc_ireg (cfg);
5815                         ins->sreg1 = args [0]->dreg;
5816                         ins->sreg2 = args [1]->dreg;
5817                         ins->sreg3 = args [2]->dreg;
5818                         ins->type = STACK_I4;
5819                         MONO_ADD_INS (cfg->cbb, ins);
5820
5821                         /* bool result = r == comparand; */
5822                         MONO_INST_NEW (cfg, cmp, OP_ICOMPARE);
5823                         cmp->sreg1 = ins->dreg;
5824                         cmp->sreg2 = args [2]->dreg;
5825                         cmp->type = STACK_I4;
5826                         MONO_ADD_INS (cfg->cbb, cmp);
5827
5828                         MONO_INST_NEW (cfg, ceq, OP_ICEQ);
5829                         ceq->dreg = alloc_ireg (cfg);
5830                         ceq->type = STACK_I4;
5831                         MONO_ADD_INS (cfg->cbb, ceq);
5832
5833                         /* *success = result; */
5834                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, args [3]->dreg, 0, ceq->dreg);
5835
5836                         cfg->has_atomic_cas_i4 = TRUE;
5837                 }
5838                 else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0)
5839                         ins = emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5840
5841                 if (ins)
5842                         return ins;
5843         } else if (cmethod->klass->image == mono_defaults.corlib &&
5844                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
5845                            (strcmp (cmethod->klass->name, "Volatile") == 0)) {
5846                 ins = NULL;
5847
5848                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Read") && fsig->param_count == 1) {
5849                         guint32 opcode = 0;
5850                         MonoType *t = fsig->params [0];
5851                         gboolean is_ref;
5852                         gboolean is_float = t->type == MONO_TYPE_R4 || t->type == MONO_TYPE_R8;
5853
5854                         g_assert (t->byref);
5855                         /* t is a byref type, so the reference check is more complicated */
5856                         is_ref = mini_type_is_reference (&mono_class_from_mono_type (t)->byval_arg);
5857                         if (t->type == MONO_TYPE_I1)
5858                                 opcode = OP_ATOMIC_LOAD_I1;
5859                         else if (t->type == MONO_TYPE_U1 || t->type == MONO_TYPE_BOOLEAN)
5860                                 opcode = OP_ATOMIC_LOAD_U1;
5861                         else if (t->type == MONO_TYPE_I2)
5862                                 opcode = OP_ATOMIC_LOAD_I2;
5863                         else if (t->type == MONO_TYPE_U2)
5864                                 opcode = OP_ATOMIC_LOAD_U2;
5865                         else if (t->type == MONO_TYPE_I4)
5866                                 opcode = OP_ATOMIC_LOAD_I4;
5867                         else if (t->type == MONO_TYPE_U4)
5868                                 opcode = OP_ATOMIC_LOAD_U4;
5869                         else if (t->type == MONO_TYPE_R4)
5870                                 opcode = OP_ATOMIC_LOAD_R4;
5871                         else if (t->type == MONO_TYPE_R8)
5872                                 opcode = OP_ATOMIC_LOAD_R8;
5873 #if SIZEOF_REGISTER == 8
5874                         else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_I)
5875                                 opcode = OP_ATOMIC_LOAD_I8;
5876                         else if (is_ref || t->type == MONO_TYPE_U8 || t->type == MONO_TYPE_U)
5877                                 opcode = OP_ATOMIC_LOAD_U8;
5878 #else
5879                         else if (t->type == MONO_TYPE_I)
5880                                 opcode = OP_ATOMIC_LOAD_I4;
5881                         else if (is_ref || t->type == MONO_TYPE_U)
5882                                 opcode = OP_ATOMIC_LOAD_U4;
5883 #endif
5884
5885                         if (opcode) {
5886                                 if (!mono_arch_opcode_supported (opcode))
5887                                         return NULL;
5888
5889                                 MONO_INST_NEW (cfg, ins, opcode);
5890                                 ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : (is_float ? mono_alloc_freg (cfg) : mono_alloc_ireg (cfg));
5891                                 ins->sreg1 = args [0]->dreg;
5892                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_ACQ;
5893                                 MONO_ADD_INS (cfg->cbb, ins);
5894
5895                                 switch (t->type) {
5896                                 case MONO_TYPE_BOOLEAN:
5897                                 case MONO_TYPE_I1:
5898                                 case MONO_TYPE_U1:
5899                                 case MONO_TYPE_I2:
5900                                 case MONO_TYPE_U2:
5901                                 case MONO_TYPE_I4:
5902                                 case MONO_TYPE_U4:
5903                                         ins->type = STACK_I4;
5904                                         break;
5905                                 case MONO_TYPE_I8:
5906                                 case MONO_TYPE_U8:
5907                                         ins->type = STACK_I8;
5908                                         break;
5909                                 case MONO_TYPE_I:
5910                                 case MONO_TYPE_U:
5911 #if SIZEOF_REGISTER == 8
5912                                         ins->type = STACK_I8;
5913 #else
5914                                         ins->type = STACK_I4;
5915 #endif
5916                                         break;
5917                                 case MONO_TYPE_R4:
5918                                         ins->type = cfg->r4_stack_type;
5919                                         break;
5920                                 case MONO_TYPE_R8:
5921                                         ins->type = STACK_R8;
5922                                         break;
5923                                 default:
5924                                         g_assert (is_ref);
5925                                         ins->type = STACK_OBJ;
5926                                         break;
5927                                 }
5928                         }
5929                 }
5930
5931                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Write") && fsig->param_count == 2) {
5932                         guint32 opcode = 0;
5933                         MonoType *t = fsig->params [0];
5934                         gboolean is_ref;
5935
5936                         g_assert (t->byref);
5937                         is_ref = mini_type_is_reference (&mono_class_from_mono_type (t)->byval_arg);
5938                         if (t->type == MONO_TYPE_I1)
5939                                 opcode = OP_ATOMIC_STORE_I1;
5940                         else if (t->type == MONO_TYPE_U1 || t->type == MONO_TYPE_BOOLEAN)
5941                                 opcode = OP_ATOMIC_STORE_U1;
5942                         else if (t->type == MONO_TYPE_I2)
5943                                 opcode = OP_ATOMIC_STORE_I2;
5944                         else if (t->type == MONO_TYPE_U2)
5945                                 opcode = OP_ATOMIC_STORE_U2;
5946                         else if (t->type == MONO_TYPE_I4)
5947                                 opcode = OP_ATOMIC_STORE_I4;
5948                         else if (t->type == MONO_TYPE_U4)
5949                                 opcode = OP_ATOMIC_STORE_U4;
5950                         else if (t->type == MONO_TYPE_R4)
5951                                 opcode = OP_ATOMIC_STORE_R4;
5952                         else if (t->type == MONO_TYPE_R8)
5953                                 opcode = OP_ATOMIC_STORE_R8;
5954 #if SIZEOF_REGISTER == 8
5955                         else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_I)
5956                                 opcode = OP_ATOMIC_STORE_I8;
5957                         else if (is_ref || t->type == MONO_TYPE_U8 || t->type == MONO_TYPE_U)
5958                                 opcode = OP_ATOMIC_STORE_U8;
5959 #else
5960                         else if (t->type == MONO_TYPE_I)
5961                                 opcode = OP_ATOMIC_STORE_I4;
5962                         else if (is_ref || t->type == MONO_TYPE_U)
5963                                 opcode = OP_ATOMIC_STORE_U4;
5964 #endif
5965
5966                         if (opcode) {
5967                                 if (!mono_arch_opcode_supported (opcode))
5968                                         return NULL;
5969
5970                                 MONO_INST_NEW (cfg, ins, opcode);
5971                                 ins->dreg = args [0]->dreg;
5972                                 ins->sreg1 = args [1]->dreg;
5973                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_REL;
5974                                 MONO_ADD_INS (cfg->cbb, ins);
5975
5976                                 if (cfg->gen_write_barriers && is_ref)
5977                                         emit_write_barrier (cfg, args [0], args [1]);
5978                         }
5979                 }
5980
5981                 if (ins)
5982                         return ins;
5983         } else if (cmethod->klass->image == mono_defaults.corlib &&
5984                            (strcmp (cmethod->klass->name_space, "System.Diagnostics") == 0) &&
5985                            (strcmp (cmethod->klass->name, "Debugger") == 0)) {
5986                 if (!strcmp (cmethod->name, "Break") && fsig->param_count == 0) {
5987                         if (should_insert_brekpoint (cfg->method)) {
5988                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
5989                         } else {
5990                                 MONO_INST_NEW (cfg, ins, OP_NOP);
5991                                 MONO_ADD_INS (cfg->cbb, ins);
5992                         }
5993                         return ins;
5994                 }
5995         } else if (cmethod->klass->image == mono_defaults.corlib &&
5996                    (strcmp (cmethod->klass->name_space, "System") == 0) &&
5997                    (strcmp (cmethod->klass->name, "Environment") == 0)) {
5998                 if (!strcmp (cmethod->name, "get_IsRunningOnWindows") && fsig->param_count == 0) {
5999 #ifdef TARGET_WIN32
6000                         EMIT_NEW_ICONST (cfg, ins, 1);
6001 #else
6002                         EMIT_NEW_ICONST (cfg, ins, 0);
6003 #endif
6004                 }
6005         } else if (cmethod->klass->image == mono_defaults.corlib &&
6006                            (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
6007                            (strcmp (cmethod->klass->name, "Assembly") == 0)) {
6008                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetExecutingAssembly")) {
6009                         /* No stack walks are currently available, so implement this as an intrinsic */
6010                         MonoInst *assembly_ins;
6011
6012                         EMIT_NEW_AOTCONST (cfg, assembly_ins, MONO_PATCH_INFO_IMAGE, cfg->method->klass->image);
6013                         ins = mono_emit_jit_icall (cfg, mono_get_assembly_object, &assembly_ins);
6014                         return ins;
6015                 }
6016         } else if (cmethod->klass->image == mono_defaults.corlib &&
6017                            (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
6018                            (strcmp (cmethod->klass->name, "MethodBase") == 0)) {
6019                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetCurrentMethod")) {
6020                         /* No stack walks are currently available, so implement this as an intrinsic */
6021                         MonoInst *method_ins;
6022                         MonoMethod *declaring = cfg->method;
6023
6024                         /* This returns the declaring generic method */
6025                         if (declaring->is_inflated)
6026                                 declaring = ((MonoMethodInflated*)cfg->method)->declaring;
6027                         EMIT_NEW_AOTCONST (cfg, method_ins, MONO_PATCH_INFO_METHODCONST, declaring);
6028                         ins = mono_emit_jit_icall (cfg, mono_get_method_object, &method_ins);
6029                         cfg->no_inline = TRUE;
6030                         if (cfg->method != cfg->current_method)
6031                                 inline_failure (cfg, "MethodBase:GetCurrentMethod ()");
6032                         return ins;
6033                 }
6034         } else if (cmethod->klass == mono_defaults.math_class) {
6035                 /* 
6036                  * There is general branchless code for Min/Max, but it does not work for 
6037                  * all inputs:
6038                  * http://everything2.com/?node_id=1051618
6039                  */
6040         } else if (cmethod->klass == mono_defaults.systemtype_class && !strcmp (cmethod->name, "op_Equality")) {
6041                 EMIT_NEW_BIALU (cfg, ins, OP_COMPARE, -1, args [0]->dreg, args [1]->dreg);
6042                 MONO_INST_NEW (cfg, ins, OP_PCEQ);
6043                 ins->dreg = alloc_preg (cfg);
6044                 ins->type = STACK_I4;
6045                 MONO_ADD_INS (cfg->cbb, ins);
6046                 return ins;
6047         } else if (((!strcmp (cmethod->klass->image->assembly->aname.name, "MonoMac") ||
6048                     !strcmp (cmethod->klass->image->assembly->aname.name, "monotouch")) &&
6049                                 !strcmp (cmethod->klass->name_space, "XamCore.ObjCRuntime") &&
6050                                 !strcmp (cmethod->klass->name, "Selector")) ||
6051                            ((!strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.iOS") ||
6052                                  !strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.Mac")) &&
6053                                 !strcmp (cmethod->klass->name_space, "ObjCRuntime") &&
6054                                 !strcmp (cmethod->klass->name, "Selector"))
6055                            ) {
6056                 if ((cfg->backend->have_objc_get_selector || cfg->compile_llvm) &&
6057                         !strcmp (cmethod->name, "GetHandle") && fsig->param_count == 1 &&
6058                     (args [0]->opcode == OP_GOT_ENTRY || args [0]->opcode == OP_AOTCONST) &&
6059                     cfg->compile_aot) {
6060                         MonoInst *pi;
6061                         MonoJumpInfoToken *ji;
6062                         char *s;
6063
6064                         if (args [0]->opcode == OP_GOT_ENTRY) {
6065                                 pi = (MonoInst *)args [0]->inst_p1;
6066                                 g_assert (pi->opcode == OP_PATCH_INFO);
6067                                 g_assert (GPOINTER_TO_INT (pi->inst_p1) == MONO_PATCH_INFO_LDSTR);
6068                                 ji = (MonoJumpInfoToken *)pi->inst_p0;
6069                         } else {
6070                                 g_assert (GPOINTER_TO_INT (args [0]->inst_p1) == MONO_PATCH_INFO_LDSTR);
6071                                 ji = (MonoJumpInfoToken *)args [0]->inst_p0;
6072                         }
6073
6074                         NULLIFY_INS (args [0]);
6075
6076                         s = mono_ldstr_utf8 (ji->image, mono_metadata_token_index (ji->token), &cfg->error);
6077                         return_val_if_nok (&cfg->error, NULL);
6078
6079                         MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
6080                         ins->dreg = mono_alloc_ireg (cfg);
6081                         // FIXME: Leaks
6082                         ins->inst_p0 = s;
6083                         MONO_ADD_INS (cfg->cbb, ins);
6084                         return ins;
6085                 }
6086         }
6087
6088 #ifdef MONO_ARCH_SIMD_INTRINSICS
6089         if (cfg->opt & MONO_OPT_SIMD) {
6090                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
6091                 if (ins)
6092                         return ins;
6093         }
6094 #endif
6095
6096         ins = mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
6097         if (ins)
6098                 return ins;
6099
6100         if (COMPILE_LLVM (cfg)) {
6101                 ins = llvm_emit_inst_for_method (cfg, cmethod, fsig, args);
6102                 if (ins)
6103                         return ins;
6104         }
6105
6106         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
6107 }
6108
6109 /*
6110  * This entry point could be used later for arbitrary method
6111  * redirection.
6112  */
6113 inline static MonoInst*
6114 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
6115                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this_ins)
6116 {
6117         if (method->klass == mono_defaults.string_class) {
6118                 /* managed string allocation support */
6119                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
6120                         MonoInst *iargs [2];
6121                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
6122                         MonoMethod *managed_alloc = NULL;
6123
6124                         g_assert (vtable); /*Should not fail since it System.String*/
6125 #ifndef MONO_CROSS_COMPILE
6126                         managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE, FALSE);
6127 #endif
6128                         if (!managed_alloc)
6129                                 return NULL;
6130                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
6131                         iargs [1] = args [0];
6132                         return mono_emit_method_call (cfg, managed_alloc, iargs, this_ins);
6133                 }
6134         }
6135         return NULL;
6136 }
6137
6138 static void
6139 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
6140 {
6141         MonoInst *store, *temp;
6142         int i;
6143
6144         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
6145                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
6146
6147                 /*
6148                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
6149                  * would be different than the MonoInst's used to represent arguments, and
6150                  * the ldelema implementation can't deal with that.
6151                  * Solution: When ldelema is used on an inline argument, create a var for 
6152                  * it, emit ldelema on that var, and emit the saving code below in
6153                  * inline_method () if needed.
6154                  */
6155                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
6156                 cfg->args [i] = temp;
6157                 /* This uses cfg->args [i] which is set by the preceeding line */
6158                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
6159                 store->cil_code = sp [0]->cil_code;
6160                 sp++;
6161         }
6162 }
6163
6164 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
6165 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
6166
6167 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6168 static gboolean
6169 check_inline_called_method_name_limit (MonoMethod *called_method)
6170 {
6171         int strncmp_result;
6172         static const char *limit = NULL;
6173         
6174         if (limit == NULL) {
6175                 const char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
6176
6177                 if (limit_string != NULL)
6178                         limit = limit_string;
6179                 else
6180                         limit = "";
6181         }
6182
6183         if (limit [0] != '\0') {
6184                 char *called_method_name = mono_method_full_name (called_method, TRUE);
6185
6186                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
6187                 g_free (called_method_name);
6188         
6189                 //return (strncmp_result <= 0);
6190                 return (strncmp_result == 0);
6191         } else {
6192                 return TRUE;
6193         }
6194 }
6195 #endif
6196
6197 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6198 static gboolean
6199 check_inline_caller_method_name_limit (MonoMethod *caller_method)
6200 {
6201         int strncmp_result;
6202         static const char *limit = NULL;
6203         
6204         if (limit == NULL) {
6205                 const char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
6206                 if (limit_string != NULL) {
6207                         limit = limit_string;
6208                 } else {
6209                         limit = "";
6210                 }
6211         }
6212
6213         if (limit [0] != '\0') {
6214                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
6215
6216                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
6217                 g_free (caller_method_name);
6218         
6219                 //return (strncmp_result <= 0);
6220                 return (strncmp_result == 0);
6221         } else {
6222                 return TRUE;
6223         }
6224 }
6225 #endif
6226
6227 static void
6228 emit_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6229 {
6230         static double r8_0 = 0.0;
6231         static float r4_0 = 0.0;
6232         MonoInst *ins;
6233         int t;
6234
6235         rtype = mini_get_underlying_type (rtype);
6236         t = rtype->type;
6237
6238         if (rtype->byref) {
6239                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6240         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6241                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
6242         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6243                 MONO_EMIT_NEW_I8CONST (cfg, dreg, 0);
6244         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6245                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
6246                 ins->type = STACK_R4;
6247                 ins->inst_p0 = (void*)&r4_0;
6248                 ins->dreg = dreg;
6249                 MONO_ADD_INS (cfg->cbb, ins);
6250         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6251                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
6252                 ins->type = STACK_R8;
6253                 ins->inst_p0 = (void*)&r8_0;
6254                 ins->dreg = dreg;
6255                 MONO_ADD_INS (cfg->cbb, ins);
6256         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6257                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6258                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6259         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
6260                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6261         } else {
6262                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6263         }
6264 }
6265
6266 static void
6267 emit_dummy_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6268 {
6269         int t;
6270
6271         rtype = mini_get_underlying_type (rtype);
6272         t = rtype->type;
6273
6274         if (rtype->byref) {
6275                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_PCONST);
6276         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6277                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_ICONST);
6278         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6279                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_I8CONST);
6280         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6281                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R4CONST);
6282         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6283                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R8CONST);
6284         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6285                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6286                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6287         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
6288                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6289         } else {
6290                 emit_init_rvar (cfg, dreg, rtype);
6291         }
6292 }
6293
6294 /* If INIT is FALSE, emit dummy initialization statements to keep the IR valid */
6295 static void
6296 emit_init_local (MonoCompile *cfg, int local, MonoType *type, gboolean init)
6297 {
6298         MonoInst *var = cfg->locals [local];
6299         if (COMPILE_SOFT_FLOAT (cfg)) {
6300                 MonoInst *store;
6301                 int reg = alloc_dreg (cfg, (MonoStackType)var->type);
6302                 emit_init_rvar (cfg, reg, type);
6303                 EMIT_NEW_LOCSTORE (cfg, store, local, cfg->cbb->last_ins);
6304         } else {
6305                 if (init)
6306                         emit_init_rvar (cfg, var->dreg, type);
6307                 else
6308                         emit_dummy_init_rvar (cfg, var->dreg, type);
6309         }
6310 }
6311
6312 int
6313 mini_inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp, guchar *ip, guint real_offset, gboolean inline_always)
6314 {
6315         return inline_method (cfg, cmethod, fsig, sp, ip, real_offset, inline_always);
6316 }
6317
6318 /*
6319  * inline_method:
6320  *
6321  * Return the cost of inlining CMETHOD, or zero if it should not be inlined.
6322  */
6323 static int
6324 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
6325                guchar *ip, guint real_offset, gboolean inline_always)
6326 {
6327         MonoError error;
6328         MonoInst *ins, *rvar = NULL;
6329         MonoMethodHeader *cheader;
6330         MonoBasicBlock *ebblock, *sbblock;
6331         int i, costs;
6332         MonoMethod *prev_inlined_method;
6333         MonoInst **prev_locals, **prev_args;
6334         MonoType **prev_arg_types;
6335         guint prev_real_offset;
6336         GHashTable *prev_cbb_hash;
6337         MonoBasicBlock **prev_cil_offset_to_bb;
6338         MonoBasicBlock *prev_cbb;
6339         const unsigned char *prev_ip;
6340         unsigned char *prev_cil_start;
6341         guint32 prev_cil_offset_to_bb_len;
6342         MonoMethod *prev_current_method;
6343         MonoGenericContext *prev_generic_context;
6344         gboolean ret_var_set, prev_ret_var_set, prev_disable_inline, virtual_ = FALSE;
6345
6346         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
6347
6348 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6349         if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
6350                 return 0;
6351 #endif
6352 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6353         if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
6354                 return 0;
6355 #endif
6356
6357         if (!fsig)
6358                 fsig = mono_method_signature (cmethod);
6359
6360         if (cfg->verbose_level > 2)
6361                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6362
6363         if (!cmethod->inline_info) {
6364                 cfg->stat_inlineable_methods++;
6365                 cmethod->inline_info = 1;
6366         }
6367
6368         /* allocate local variables */
6369         cheader = mono_method_get_header_checked (cmethod, &error);
6370         if (!cheader) {
6371                 if (inline_always) {
6372                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
6373                         mono_error_move (&cfg->error, &error);
6374                 } else {
6375                         mono_error_cleanup (&error);
6376                 }
6377                 return 0;
6378         }
6379
6380         /*Must verify before creating locals as it can cause the JIT to assert.*/
6381         if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
6382                 mono_metadata_free_mh (cheader);
6383                 return 0;
6384         }
6385
6386         /* allocate space to store the return value */
6387         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
6388                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
6389         }
6390
6391         prev_locals = cfg->locals;
6392         cfg->locals = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));
6393         for (i = 0; i < cheader->num_locals; ++i)
6394                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
6395
6396         /* allocate start and end blocks */
6397         /* This is needed so if the inline is aborted, we can clean up */
6398         NEW_BBLOCK (cfg, sbblock);
6399         sbblock->real_offset = real_offset;
6400
6401         NEW_BBLOCK (cfg, ebblock);
6402         ebblock->block_num = cfg->num_bblocks++;
6403         ebblock->real_offset = real_offset;
6404
6405         prev_args = cfg->args;
6406         prev_arg_types = cfg->arg_types;
6407         prev_inlined_method = cfg->inlined_method;
6408         cfg->inlined_method = cmethod;
6409         cfg->ret_var_set = FALSE;
6410         cfg->inline_depth ++;
6411         prev_real_offset = cfg->real_offset;
6412         prev_cbb_hash = cfg->cbb_hash;
6413         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
6414         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
6415         prev_cil_start = cfg->cil_start;
6416         prev_ip = cfg->ip;
6417         prev_cbb = cfg->cbb;
6418         prev_current_method = cfg->current_method;
6419         prev_generic_context = cfg->generic_context;
6420         prev_ret_var_set = cfg->ret_var_set;
6421         prev_disable_inline = cfg->disable_inline;
6422
6423         if (ip && *ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
6424                 virtual_ = TRUE;
6425
6426         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, sp, real_offset, virtual_);
6427
6428         ret_var_set = cfg->ret_var_set;
6429
6430         cfg->inlined_method = prev_inlined_method;
6431         cfg->real_offset = prev_real_offset;
6432         cfg->cbb_hash = prev_cbb_hash;
6433         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
6434         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
6435         cfg->cil_start = prev_cil_start;
6436         cfg->ip = prev_ip;
6437         cfg->locals = prev_locals;
6438         cfg->args = prev_args;
6439         cfg->arg_types = prev_arg_types;
6440         cfg->current_method = prev_current_method;
6441         cfg->generic_context = prev_generic_context;
6442         cfg->ret_var_set = prev_ret_var_set;
6443         cfg->disable_inline = prev_disable_inline;
6444         cfg->inline_depth --;
6445
6446         if ((costs >= 0 && costs < 60) || inline_always || (costs >= 0 && (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))) {
6447                 if (cfg->verbose_level > 2)
6448                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6449
6450                 cfg->stat_inlined_methods++;
6451
6452                 /* always add some code to avoid block split failures */
6453                 MONO_INST_NEW (cfg, ins, OP_NOP);
6454                 MONO_ADD_INS (prev_cbb, ins);
6455
6456                 prev_cbb->next_bb = sbblock;
6457                 link_bblock (cfg, prev_cbb, sbblock);
6458
6459                 /* 
6460                  * Get rid of the begin and end bblocks if possible to aid local
6461                  * optimizations.
6462                  */
6463                 mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
6464
6465                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
6466                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
6467
6468                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
6469                         MonoBasicBlock *prev = ebblock->in_bb [0];
6470
6471                         if (prev->next_bb == ebblock) {
6472                                 mono_merge_basic_blocks (cfg, prev, ebblock);
6473                                 cfg->cbb = prev;
6474                                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
6475                                         mono_merge_basic_blocks (cfg, prev_cbb, prev);
6476                                         cfg->cbb = prev_cbb;
6477                                 }
6478                         } else {
6479                                 /* There could be a bblock after 'prev', and making 'prev' the current bb could cause problems */
6480                                 cfg->cbb = ebblock;
6481                         }
6482                 } else {
6483                         /* 
6484                          * Its possible that the rvar is set in some prev bblock, but not in others.
6485                          * (#1835).
6486                          */
6487                         if (rvar) {
6488                                 MonoBasicBlock *bb;
6489
6490                                 for (i = 0; i < ebblock->in_count; ++i) {
6491                                         bb = ebblock->in_bb [i];
6492
6493                                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
6494                                                 cfg->cbb = bb;
6495
6496                                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
6497                                         }
6498                                 }
6499                         }
6500
6501                         cfg->cbb = ebblock;
6502                 }
6503
6504                 if (rvar) {
6505                         /*
6506                          * If the inlined method contains only a throw, then the ret var is not 
6507                          * set, so set it to a dummy value.
6508                          */
6509                         if (!ret_var_set)
6510                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
6511
6512                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
6513                         *sp++ = ins;
6514                 }
6515                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
6516                 return costs + 1;
6517         } else {
6518                 if (cfg->verbose_level > 2)
6519                         printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
6520                 cfg->exception_type = MONO_EXCEPTION_NONE;
6521
6522                 /* This gets rid of the newly added bblocks */
6523                 cfg->cbb = prev_cbb;
6524         }
6525         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
6526         return 0;
6527 }
6528
6529 /*
6530  * Some of these comments may well be out-of-date.
6531  * Design decisions: we do a single pass over the IL code (and we do bblock 
6532  * splitting/merging in the few cases when it's required: a back jump to an IL
6533  * address that was not already seen as bblock starting point).
6534  * Code is validated as we go (full verification is still better left to metadata/verify.c).
6535  * Complex operations are decomposed in simpler ones right away. We need to let the 
6536  * arch-specific code peek and poke inside this process somehow (except when the 
6537  * optimizations can take advantage of the full semantic info of coarse opcodes).
6538  * All the opcodes of the form opcode.s are 'normalized' to opcode.
6539  * MonoInst->opcode initially is the IL opcode or some simplification of that 
6540  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
6541  * opcode with value bigger than OP_LAST.
6542  * At this point the IR can be handed over to an interpreter, a dumb code generator
6543  * or to the optimizing code generator that will translate it to SSA form.
6544  *
6545  * Profiling directed optimizations.
6546  * We may compile by default with few or no optimizations and instrument the code
6547  * or the user may indicate what methods to optimize the most either in a config file
6548  * or through repeated runs where the compiler applies offline the optimizations to 
6549  * each method and then decides if it was worth it.
6550  */
6551
6552 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
6553 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
6554 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
6555 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
6556 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
6557 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
6558 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
6559 #define CHECK_TYPELOAD(klass) if (!(klass) || mono_class_has_failure (klass)) TYPE_LOAD_ERROR ((klass))
6560
6561 /* offset from br.s -> br like opcodes */
6562 #define BIG_BRANCH_OFFSET 13
6563
6564 static gboolean
6565 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
6566 {
6567         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
6568
6569         return b == NULL || b == bb;
6570 }
6571
6572 static int
6573 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
6574 {
6575         unsigned char *ip = start;
6576         unsigned char *target;
6577         int i;
6578         guint cli_addr;
6579         MonoBasicBlock *bblock;
6580         const MonoOpcode *opcode;
6581
6582         while (ip < end) {
6583                 cli_addr = ip - start;
6584                 i = mono_opcode_value ((const guint8 **)&ip, end);
6585                 if (i < 0)
6586                         UNVERIFIED;
6587                 opcode = &mono_opcodes [i];
6588                 switch (opcode->argument) {
6589                 case MonoInlineNone:
6590                         ip++; 
6591                         break;
6592                 case MonoInlineString:
6593                 case MonoInlineType:
6594                 case MonoInlineField:
6595                 case MonoInlineMethod:
6596                 case MonoInlineTok:
6597                 case MonoInlineSig:
6598                 case MonoShortInlineR:
6599                 case MonoInlineI:
6600                         ip += 5;
6601                         break;
6602                 case MonoInlineVar:
6603                         ip += 3;
6604                         break;
6605                 case MonoShortInlineVar:
6606                 case MonoShortInlineI:
6607                         ip += 2;
6608                         break;
6609                 case MonoShortInlineBrTarget:
6610                         target = start + cli_addr + 2 + (signed char)ip [1];
6611                         GET_BBLOCK (cfg, bblock, target);
6612                         ip += 2;
6613                         if (ip < end)
6614                                 GET_BBLOCK (cfg, bblock, ip);
6615                         break;
6616                 case MonoInlineBrTarget:
6617                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
6618                         GET_BBLOCK (cfg, bblock, target);
6619                         ip += 5;
6620                         if (ip < end)
6621                                 GET_BBLOCK (cfg, bblock, ip);
6622                         break;
6623                 case MonoInlineSwitch: {
6624                         guint32 n = read32 (ip + 1);
6625                         guint32 j;
6626                         ip += 5;
6627                         cli_addr += 5 + 4 * n;
6628                         target = start + cli_addr;
6629                         GET_BBLOCK (cfg, bblock, target);
6630                         
6631                         for (j = 0; j < n; ++j) {
6632                                 target = start + cli_addr + (gint32)read32 (ip);
6633                                 GET_BBLOCK (cfg, bblock, target);
6634                                 ip += 4;
6635                         }
6636                         break;
6637                 }
6638                 case MonoInlineR:
6639                 case MonoInlineI8:
6640                         ip += 9;
6641                         break;
6642                 default:
6643                         g_assert_not_reached ();
6644                 }
6645
6646                 if (i == CEE_THROW) {
6647                         unsigned char *bb_start = ip - 1;
6648                         
6649                         /* Find the start of the bblock containing the throw */
6650                         bblock = NULL;
6651                         while ((bb_start >= start) && !bblock) {
6652                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
6653                                 bb_start --;
6654                         }
6655                         if (bblock)
6656                                 bblock->out_of_line = 1;
6657                 }
6658         }
6659         return 0;
6660 unverified:
6661 exception_exit:
6662         *pos = ip;
6663         return 1;
6664 }
6665
6666 static inline MonoMethod *
6667 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context, MonoError *error)
6668 {
6669         MonoMethod *method;
6670
6671         mono_error_init (error);
6672
6673         if (m->wrapper_type != MONO_WRAPPER_NONE) {
6674                 method = (MonoMethod *)mono_method_get_wrapper_data (m, token);
6675                 if (context) {
6676                         method = mono_class_inflate_generic_method_checked (method, context, error);
6677                 }
6678         } else {
6679                 method = mono_get_method_checked (m->klass->image, token, klass, context, error);
6680         }
6681
6682         return method;
6683 }
6684
6685 static inline MonoMethod *
6686 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
6687 {
6688         MonoError error;
6689         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context, cfg ? &cfg->error : &error);
6690
6691         if (method && cfg && !cfg->gshared && mono_class_is_open_constructed_type (&method->klass->byval_arg)) {
6692                 mono_error_set_bad_image (&cfg->error, cfg->method->klass->image, "Method with open type while not compiling gshared");
6693                 method = NULL;
6694         }
6695
6696         if (!method && !cfg)
6697                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
6698
6699         return method;
6700 }
6701
6702 static inline MonoClass*
6703 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
6704 {
6705         MonoError error;
6706         MonoClass *klass;
6707
6708         if (method->wrapper_type != MONO_WRAPPER_NONE) {
6709                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
6710                 if (context) {
6711                         klass = mono_class_inflate_generic_class_checked (klass, context, &error);
6712                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
6713                 }
6714         } else {
6715                 klass = mono_class_get_and_inflate_typespec_checked (method->klass->image, token, context, &error);
6716                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
6717         }
6718         if (klass)
6719                 mono_class_init (klass);
6720         return klass;
6721 }
6722
6723 static inline MonoMethodSignature*
6724 mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context, MonoError *error)
6725 {
6726         MonoMethodSignature *fsig;
6727
6728         mono_error_init (error);
6729         if (method->wrapper_type != MONO_WRAPPER_NONE) {
6730                 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
6731         } else {
6732                 fsig = mono_metadata_parse_signature_checked (method->klass->image, token, error);
6733                 return_val_if_nok (error, NULL);
6734         }
6735         if (context) {
6736                 fsig = mono_inflate_generic_signature(fsig, context, error);
6737         }
6738         return fsig;
6739 }
6740
6741 static MonoMethod*
6742 throw_exception (void)
6743 {
6744         static MonoMethod *method = NULL;
6745
6746         if (!method) {
6747                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
6748                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
6749         }
6750         g_assert (method);
6751         return method;
6752 }
6753
6754 static void
6755 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
6756 {
6757         MonoMethod *thrower = throw_exception ();
6758         MonoInst *args [1];
6759
6760         EMIT_NEW_PCONST (cfg, args [0], ex);
6761         mono_emit_method_call (cfg, thrower, args, NULL);
6762 }
6763
6764 /*
6765  * Return the original method is a wrapper is specified. We can only access 
6766  * the custom attributes from the original method.
6767  */
6768 static MonoMethod*
6769 get_original_method (MonoMethod *method)
6770 {
6771         if (method->wrapper_type == MONO_WRAPPER_NONE)
6772                 return method;
6773
6774         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
6775         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
6776                 return NULL;
6777
6778         /* in other cases we need to find the original method */
6779         return mono_marshal_method_from_wrapper (method);
6780 }
6781
6782 static void
6783 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field)
6784 {
6785         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
6786         MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
6787         if (ex)
6788                 emit_throw_exception (cfg, ex);
6789 }
6790
6791 static void
6792 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
6793 {
6794         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
6795         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
6796         if (ex)
6797                 emit_throw_exception (cfg, ex);
6798 }
6799
6800 /*
6801  * Check that the IL instructions at ip are the array initialization
6802  * sequence and return the pointer to the data and the size.
6803  */
6804 static const char*
6805 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
6806 {
6807         /*
6808          * newarr[System.Int32]
6809          * dup
6810          * ldtoken field valuetype ...
6811          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
6812          */
6813         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
6814                 MonoError error;
6815                 guint32 token = read32 (ip + 7);
6816                 guint32 field_token = read32 (ip + 2);
6817                 guint32 field_index = field_token & 0xffffff;
6818                 guint32 rva;
6819                 const char *data_ptr;
6820                 int size = 0;
6821                 MonoMethod *cmethod;
6822                 MonoClass *dummy_class;
6823                 MonoClassField *field = mono_field_from_token_checked (method->klass->image, field_token, &dummy_class, NULL, &error);
6824                 int dummy_align;
6825
6826                 if (!field) {
6827                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
6828                         return NULL;
6829                 }
6830
6831                 *out_field_token = field_token;
6832
6833                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
6834                 if (!cmethod)
6835                         return NULL;
6836                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
6837                         return NULL;
6838                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
6839                 case MONO_TYPE_BOOLEAN:
6840                 case MONO_TYPE_I1:
6841                 case MONO_TYPE_U1:
6842                         size = 1; break;
6843                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
6844 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
6845                 case MONO_TYPE_CHAR:
6846                 case MONO_TYPE_I2:
6847                 case MONO_TYPE_U2:
6848                         size = 2; break;
6849                 case MONO_TYPE_I4:
6850                 case MONO_TYPE_U4:
6851                 case MONO_TYPE_R4:
6852                         size = 4; break;
6853                 case MONO_TYPE_R8:
6854                 case MONO_TYPE_I8:
6855                 case MONO_TYPE_U8:
6856                         size = 8; break;
6857 #endif
6858                 default:
6859                         return NULL;
6860                 }
6861                 size *= len;
6862                 if (size > mono_type_size (field->type, &dummy_align))
6863                     return NULL;
6864                 *out_size = size;
6865                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
6866                 if (!image_is_dynamic (method->klass->image)) {
6867                         field_index = read32 (ip + 2) & 0xffffff;
6868                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
6869                         data_ptr = mono_image_rva_map (method->klass->image, rva);
6870                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
6871                         /* for aot code we do the lookup on load */
6872                         if (aot && data_ptr)
6873                                 return (const char *)GUINT_TO_POINTER (rva);
6874                 } else {
6875                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
6876                         g_assert (!aot);
6877                         data_ptr = mono_field_get_data (field);
6878                 }
6879                 return data_ptr;
6880         }
6881         return NULL;
6882 }
6883
6884 static void
6885 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
6886 {
6887         MonoError error;
6888         char *method_fname = mono_method_full_name (method, TRUE);
6889         char *method_code;
6890         MonoMethodHeader *header = mono_method_get_header_checked (method, &error);
6891
6892         if (!header) {
6893                 method_code = g_strdup_printf ("could not parse method body due to %s", mono_error_get_message (&error));
6894                 mono_error_cleanup (&error);
6895         } else if (header->code_size == 0)
6896                 method_code = g_strdup ("method body is empty.");
6897         else
6898                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
6899         mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code));
6900         g_free (method_fname);
6901         g_free (method_code);
6902         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
6903 }
6904
6905 static void
6906 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
6907 {
6908         MonoInst *ins;
6909         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
6910         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
6911                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
6912                 /* Optimize reg-reg moves away */
6913                 /* 
6914                  * Can't optimize other opcodes, since sp[0] might point to
6915                  * the last ins of a decomposed opcode.
6916                  */
6917                 sp [0]->dreg = (cfg)->locals [n]->dreg;
6918         } else {
6919                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
6920         }
6921 }
6922
6923 /*
6924  * ldloca inhibits many optimizations so try to get rid of it in common
6925  * cases.
6926  */
6927 static inline unsigned char *
6928 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
6929 {
6930         int local, token;
6931         MonoClass *klass;
6932         MonoType *type;
6933
6934         if (size == 1) {
6935                 local = ip [1];
6936                 ip += 2;
6937         } else {
6938                 local = read16 (ip + 2);
6939                 ip += 4;
6940         }
6941         
6942         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
6943                 /* From the INITOBJ case */
6944                 token = read32 (ip + 2);
6945                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
6946                 CHECK_TYPELOAD (klass);
6947                 type = mini_get_underlying_type (&klass->byval_arg);
6948                 emit_init_local (cfg, local, type, TRUE);
6949                 return ip + 6;
6950         }
6951  exception_exit:
6952         return NULL;
6953 }
6954
6955 static MonoInst*
6956 emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used, MonoInst **sp)
6957 {
6958         MonoInst *icall_args [16];
6959         MonoInst *call_target, *ins, *vtable_ins;
6960         int arg_reg, this_reg, vtable_reg;
6961         gboolean is_iface = mono_class_is_interface (cmethod->klass);
6962         gboolean is_gsharedvt = cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig);
6963         gboolean variant_iface = FALSE;
6964         guint32 slot;
6965         int offset;
6966
6967         /*
6968          * In llvm-only mode, vtables contain function descriptors instead of
6969          * method addresses/trampolines.
6970          */
6971         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
6972
6973         if (is_iface)
6974                 slot = mono_method_get_imt_slot (cmethod);
6975         else
6976                 slot = mono_method_get_vtable_index (cmethod);
6977
6978         this_reg = sp [0]->dreg;
6979
6980         if (is_iface && mono_class_has_variant_generic_params (cmethod->klass))
6981                 variant_iface = TRUE;
6982
6983         if (!fsig->generic_param_count && !is_iface && !is_gsharedvt) {
6984                 /*
6985                  * The simplest case, a normal virtual call.
6986                  */
6987                 int slot_reg = alloc_preg (cfg);
6988                 int addr_reg = alloc_preg (cfg);
6989                 int arg_reg = alloc_preg (cfg);
6990                 MonoBasicBlock *non_null_bb;
6991
6992                 vtable_reg = alloc_preg (cfg);
6993                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
6994                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + (slot * SIZEOF_VOID_P);
6995
6996                 /* Load the vtable slot, which contains a function descriptor. */
6997                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
6998
6999                 NEW_BBLOCK (cfg, non_null_bb);
7000
7001                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, slot_reg, 0);
7002                 cfg->cbb->last_ins->flags |= MONO_INST_LIKELY;
7003                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, non_null_bb);
7004
7005                 /* Slow path */
7006                 // FIXME: Make the wrapper use the preserveall cconv
7007                 // FIXME: Use one icall per slot for small slot numbers ?
7008                 icall_args [0] = vtable_ins;
7009                 EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7010                 /* Make the icall return the vtable slot value to save some code space */
7011                 ins = mono_emit_jit_icall (cfg, mono_init_vtable_slot, icall_args);
7012                 ins->dreg = slot_reg;
7013                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, non_null_bb);
7014
7015                 /* Fastpath */
7016                 MONO_START_BB (cfg, non_null_bb);
7017                 /* Load the address + arg from the vtable slot */
7018                 EMIT_NEW_LOAD_MEMBASE (cfg, call_target, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7019                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, arg_reg, slot_reg, SIZEOF_VOID_P);
7020
7021                 return emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
7022         }
7023
7024         if (!fsig->generic_param_count && is_iface && !variant_iface && !is_gsharedvt) {
7025                 /*
7026                  * A simple interface call
7027                  *
7028                  * We make a call through an imt slot to obtain the function descriptor we need to call.
7029                  * The imt slot contains a function descriptor for a runtime function + arg.
7030                  */
7031                 int slot_reg = alloc_preg (cfg);
7032                 int addr_reg = alloc_preg (cfg);
7033                 int arg_reg = alloc_preg (cfg);
7034                 MonoInst *thunk_addr_ins, *thunk_arg_ins, *ftndesc_ins;
7035
7036                 vtable_reg = alloc_preg (cfg);
7037                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7038                 offset = ((gint32)slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
7039
7040                 /*
7041                  * The slot is already initialized when the vtable is created so there is no need
7042                  * to check it here.
7043                  */
7044
7045                 /* Load the imt slot, which contains a function descriptor. */
7046                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7047
7048                 /* Load the address + arg of the imt thunk from the imt slot */
7049                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_addr_ins, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7050                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_arg_ins, OP_LOAD_MEMBASE, arg_reg, slot_reg, SIZEOF_VOID_P);
7051                 /*
7052                  * IMT thunks in llvm-only mode are C functions which take an info argument
7053                  * plus the imt method and return the ftndesc to call.
7054                  */
7055                 icall_args [0] = thunk_arg_ins;
7056                 icall_args [1] = emit_get_rgctx_method (cfg, context_used,
7057                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7058                 ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_trampoline, icall_args, thunk_addr_ins, NULL, NULL);
7059
7060                 return emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
7061         }
7062
7063         if ((fsig->generic_param_count || variant_iface) && !is_gsharedvt) {
7064                 /*
7065                  * This is similar to the interface case, the vtable slot points to an imt thunk which is
7066                  * dynamically extended as more instantiations are discovered.
7067                  * This handles generic virtual methods both on classes and interfaces.
7068                  */
7069                 int slot_reg = alloc_preg (cfg);
7070                 int addr_reg = alloc_preg (cfg);
7071                 int arg_reg = alloc_preg (cfg);
7072                 int ftndesc_reg = alloc_preg (cfg);
7073                 MonoInst *thunk_addr_ins, *thunk_arg_ins, *ftndesc_ins;
7074                 MonoBasicBlock *slowpath_bb, *end_bb;
7075
7076                 NEW_BBLOCK (cfg, slowpath_bb);
7077                 NEW_BBLOCK (cfg, end_bb);
7078
7079                 vtable_reg = alloc_preg (cfg);
7080                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7081                 if (is_iface)
7082                         offset = ((gint32)slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
7083                 else
7084                         offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + (slot * SIZEOF_VOID_P);
7085
7086                 /* Load the slot, which contains a function descriptor. */
7087                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7088
7089                 /* These slots are not initialized, so fall back to the slow path until they are initialized */
7090                 /* That happens when mono_method_add_generic_virtual_invocation () creates an IMT thunk */
7091                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, slot_reg, 0);
7092                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, slowpath_bb);
7093
7094                 /* Fastpath */
7095                 /* Same as with iface calls */
7096                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_addr_ins, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7097                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_arg_ins, OP_LOAD_MEMBASE, arg_reg, slot_reg, SIZEOF_VOID_P);
7098                 icall_args [0] = thunk_arg_ins;
7099                 icall_args [1] = emit_get_rgctx_method (cfg, context_used,
7100                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7101                 ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_trampoline, icall_args, thunk_addr_ins, NULL, NULL);
7102                 ftndesc_ins->dreg = ftndesc_reg;
7103                 /*
7104                  * Unlike normal iface calls, these imt thunks can return NULL, i.e. when they are passed an instantiation
7105                  * they don't know about yet. Fall back to the slowpath in that case.
7106                  */
7107                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ftndesc_reg, 0);
7108                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, slowpath_bb);
7109
7110                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
7111
7112                 /* Slowpath */
7113                 MONO_START_BB (cfg, slowpath_bb);
7114                 icall_args [0] = vtable_ins;
7115                 EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7116                 icall_args [2] = emit_get_rgctx_method (cfg, context_used,
7117                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7118                 if (is_iface)
7119                         ftndesc_ins = mono_emit_jit_icall (cfg, mono_resolve_generic_virtual_iface_call, icall_args);
7120                 else
7121                         ftndesc_ins = mono_emit_jit_icall (cfg, mono_resolve_generic_virtual_call, icall_args);
7122                 ftndesc_ins->dreg = ftndesc_reg;
7123                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
7124
7125                 /* Common case */
7126                 MONO_START_BB (cfg, end_bb);
7127                 return emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
7128         }
7129
7130         /*
7131          * Non-optimized cases
7132          */
7133         icall_args [0] = sp [0];
7134         EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7135
7136         icall_args [2] = emit_get_rgctx_method (cfg, context_used,
7137                                                                                         cmethod, MONO_RGCTX_INFO_METHOD);
7138
7139         arg_reg = alloc_preg (cfg);
7140         MONO_EMIT_NEW_PCONST (cfg, arg_reg, NULL);
7141         EMIT_NEW_VARLOADA_VREG (cfg, icall_args [3], arg_reg, &mono_defaults.int_class->byval_arg);
7142
7143         g_assert (is_gsharedvt);
7144         if (is_iface)
7145                 call_target = mono_emit_jit_icall (cfg, mono_resolve_iface_call_gsharedvt, icall_args);
7146         else
7147                 call_target = mono_emit_jit_icall (cfg, mono_resolve_vcall_gsharedvt, icall_args);
7148
7149         /*
7150          * Pass the extra argument even if the callee doesn't receive it, most
7151          * calling conventions allow this.
7152          */
7153         return emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
7154 }
7155
7156 static gboolean
7157 is_exception_class (MonoClass *klass)
7158 {
7159         while (klass) {
7160                 if (klass == mono_defaults.exception_class)
7161                         return TRUE;
7162                 klass = klass->parent;
7163         }
7164         return FALSE;
7165 }
7166
7167 /*
7168  * is_jit_optimizer_disabled:
7169  *
7170  *   Determine whenever M's assembly has a DebuggableAttribute with the
7171  * IsJITOptimizerDisabled flag set.
7172  */
7173 static gboolean
7174 is_jit_optimizer_disabled (MonoMethod *m)
7175 {
7176         MonoError error;
7177         MonoAssembly *ass = m->klass->image->assembly;
7178         MonoCustomAttrInfo* attrs;
7179         MonoClass *klass;
7180         int i;
7181         gboolean val = FALSE;
7182
7183         g_assert (ass);
7184         if (ass->jit_optimizer_disabled_inited)
7185                 return ass->jit_optimizer_disabled;
7186
7187         klass = mono_class_try_get_debuggable_attribute_class ();
7188
7189         if (!klass) {
7190                 /* Linked away */
7191                 ass->jit_optimizer_disabled = FALSE;
7192                 mono_memory_barrier ();
7193                 ass->jit_optimizer_disabled_inited = TRUE;
7194                 return FALSE;
7195         }
7196
7197         attrs = mono_custom_attrs_from_assembly_checked (ass, FALSE, &error);
7198         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7199         if (attrs) {
7200                 for (i = 0; i < attrs->num_attrs; ++i) {
7201                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
7202                         const gchar *p;
7203                         MonoMethodSignature *sig;
7204
7205                         if (!attr->ctor || attr->ctor->klass != klass)
7206                                 continue;
7207                         /* Decode the attribute. See reflection.c */
7208                         p = (const char*)attr->data;
7209                         g_assert (read16 (p) == 0x0001);
7210                         p += 2;
7211
7212                         // FIXME: Support named parameters
7213                         sig = mono_method_signature (attr->ctor);
7214                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
7215                                 continue;
7216                         /* Two boolean arguments */
7217                         p ++;
7218                         val = *p;
7219                 }
7220                 mono_custom_attrs_free (attrs);
7221         }
7222
7223         ass->jit_optimizer_disabled = val;
7224         mono_memory_barrier ();
7225         ass->jit_optimizer_disabled_inited = TRUE;
7226
7227         return val;
7228 }
7229
7230 static gboolean
7231 is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig, int call_opcode)
7232 {
7233         gboolean supported_tail_call;
7234         int i;
7235
7236         supported_tail_call = mono_arch_tail_call_supported (cfg, mono_method_signature (method), mono_method_signature (cmethod));
7237
7238         for (i = 0; i < fsig->param_count; ++i) {
7239                 if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
7240                         /* These can point to the current method's stack */
7241                         supported_tail_call = FALSE;
7242         }
7243         if (fsig->hasthis && cmethod->klass->valuetype)
7244                 /* this might point to the current method's stack */
7245                 supported_tail_call = FALSE;
7246         if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
7247                 supported_tail_call = FALSE;
7248         if (cfg->method->save_lmf)
7249                 supported_tail_call = FALSE;
7250         if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
7251                 supported_tail_call = FALSE;
7252         if (call_opcode != CEE_CALL)
7253                 supported_tail_call = FALSE;
7254
7255         /* Debugging support */
7256 #if 0
7257         if (supported_tail_call) {
7258                 if (!mono_debug_count ())
7259                         supported_tail_call = FALSE;
7260         }
7261 #endif
7262
7263         return supported_tail_call;
7264 }
7265
7266 /*
7267  * handle_ctor_call:
7268  *
7269  *   Handle calls made to ctors from NEWOBJ opcodes.
7270  */
7271 static void
7272 handle_ctor_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used,
7273                                   MonoInst **sp, guint8 *ip, int *inline_costs)
7274 {
7275         MonoInst *vtable_arg = NULL, *callvirt_this_arg = NULL, *ins;
7276
7277         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
7278                                         mono_method_is_generic_sharable (cmethod, TRUE)) {
7279                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
7280                         mono_class_vtable (cfg->domain, cmethod->klass);
7281                         CHECK_TYPELOAD (cmethod->klass);
7282
7283                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
7284                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
7285                 } else {
7286                         if (context_used) {
7287                                 vtable_arg = mini_emit_get_rgctx_klass (cfg, context_used,
7288                                                                                                    cmethod->klass, MONO_RGCTX_INFO_VTABLE);
7289                         } else {
7290                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
7291
7292                                 CHECK_TYPELOAD (cmethod->klass);
7293                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
7294                         }
7295                 }
7296         }
7297
7298         /* Avoid virtual calls to ctors if possible */
7299         if (mono_class_is_marshalbyref (cmethod->klass))
7300                 callvirt_this_arg = sp [0];
7301
7302         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
7303                 g_assert (MONO_TYPE_IS_VOID (fsig->ret));
7304                 CHECK_CFG_EXCEPTION;
7305         } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
7306                            mono_method_check_inlining (cfg, cmethod) &&
7307                            !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE)) {
7308                 int costs;
7309
7310                 if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, FALSE))) {
7311                         cfg->real_offset += 5;
7312
7313                         *inline_costs += costs - 5;
7314                 } else {
7315                         INLINE_FAILURE ("inline failure");
7316                         // FIXME-VT: Clean this up
7317                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
7318                                 GSHAREDVT_FAILURE(*ip);
7319                         mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
7320                 }
7321         } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
7322                 MonoInst *addr;
7323
7324                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
7325
7326                 if (cfg->llvm_only) {
7327                         // FIXME: Avoid initializing vtable_arg
7328                         emit_llvmonly_calli (cfg, fsig, sp, addr);
7329                 } else {
7330                         mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
7331                 }
7332         } else if (context_used &&
7333                            ((!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
7334                                  !mono_class_generic_sharing_enabled (cmethod->klass)) || cfg->gsharedvt)) {
7335                 MonoInst *cmethod_addr;
7336
7337                 /* Generic calls made out of gsharedvt methods cannot be patched, so use an indirect call */
7338
7339                 if (cfg->llvm_only) {
7340                         MonoInst *addr = emit_get_rgctx_method (cfg, context_used, cmethod,
7341                                                                                                         MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
7342                         emit_llvmonly_calli (cfg, fsig, sp, addr);
7343                 } else {
7344                         cmethod_addr = emit_get_rgctx_method (cfg, context_used,
7345                                                                                                   cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
7346
7347                         mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
7348                 }
7349         } else {
7350                 INLINE_FAILURE ("ctor call");
7351                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
7352                                                                                   callvirt_this_arg, NULL, vtable_arg);
7353         }
7354  exception_exit:
7355         return;
7356 }
7357
7358 static void
7359 emit_setret (MonoCompile *cfg, MonoInst *val)
7360 {
7361         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (cfg->method)->ret);
7362         MonoInst *ins;
7363
7364         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
7365                 MonoInst *ret_addr;
7366
7367                 if (!cfg->vret_addr) {
7368                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, val);
7369                 } else {
7370                         EMIT_NEW_RETLOADA (cfg, ret_addr);
7371
7372                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, val->dreg);
7373                         ins->klass = mono_class_from_mono_type (ret_type);
7374                 }
7375         } else {
7376 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
7377                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
7378                         MonoInst *iargs [1];
7379                         MonoInst *conv;
7380
7381                         iargs [0] = val;
7382                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
7383                         mono_arch_emit_setret (cfg, cfg->method, conv);
7384                 } else {
7385                         mono_arch_emit_setret (cfg, cfg->method, val);
7386                 }
7387 #else
7388                 mono_arch_emit_setret (cfg, cfg->method, val);
7389 #endif
7390         }
7391 }
7392
7393 /*
7394  * mono_method_to_ir:
7395  *
7396  * Translate the .net IL into linear IR.
7397  *
7398  * @start_bblock: if not NULL, the starting basic block, used during inlining.
7399  * @end_bblock: if not NULL, the ending basic block, used during inlining.
7400  * @return_var: if not NULL, the place where the return value is stored, used during inlining.   
7401  * @inline_args: if not NULL, contains the arguments to the inline call
7402  * @inline_offset: if not zero, the real offset from the inline call, or zero otherwise.
7403  * @is_virtual_call: whether this method is being called as a result of a call to callvirt
7404  *
7405  * This method is used to turn ECMA IL into Mono's internal Linear IR
7406  * reprensetation.  It is used both for entire methods, as well as
7407  * inlining existing methods.  In the former case, the @start_bblock,
7408  * @end_bblock, @return_var, @inline_args are all set to NULL, and the
7409  * inline_offset is set to zero.
7410  * 
7411  * Returns: the inline cost, or -1 if there was an error processing this method.
7412  */
7413 int
7414 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
7415                    MonoInst *return_var, MonoInst **inline_args, 
7416                    guint inline_offset, gboolean is_virtual_call)
7417 {
7418         MonoError error;
7419         MonoInst *ins, **sp, **stack_start;
7420         MonoBasicBlock *tblock = NULL, *init_localsbb = NULL;
7421         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
7422         MonoMethod *cmethod, *method_definition;
7423         MonoInst **arg_array;
7424         MonoMethodHeader *header;
7425         MonoImage *image;
7426         guint32 token, ins_flag;
7427         MonoClass *klass;
7428         MonoClass *constrained_class = NULL;
7429         unsigned char *ip, *end, *target, *err_pos;
7430         MonoMethodSignature *sig;
7431         MonoGenericContext *generic_context = NULL;
7432         MonoGenericContainer *generic_container = NULL;
7433         MonoType **param_types;
7434         int i, n, start_new_bblock, dreg;
7435         int num_calls = 0, inline_costs = 0;
7436         int breakpoint_id = 0;
7437         guint num_args;
7438         GSList *class_inits = NULL;
7439         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
7440         int context_used;
7441         gboolean init_locals, seq_points, skip_dead_blocks;
7442         gboolean sym_seq_points = FALSE;
7443         MonoDebugMethodInfo *minfo;
7444         MonoBitSet *seq_point_locs = NULL;
7445         MonoBitSet *seq_point_set_locs = NULL;
7446
7447         cfg->disable_inline = is_jit_optimizer_disabled (method);
7448
7449         /* serialization and xdomain stuff may need access to private fields and methods */
7450         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
7451         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
7452         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
7453         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
7454         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
7455         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
7456
7457         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
7458         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
7459         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
7460         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
7461         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
7462
7463         image = method->klass->image;
7464         header = mono_method_get_header_checked (method, &cfg->error);
7465         if (!header) {
7466                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
7467                 goto exception_exit;
7468         } else {
7469                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
7470         }
7471
7472         generic_container = mono_method_get_generic_container (method);
7473         sig = mono_method_signature (method);
7474         num_args = sig->hasthis + sig->param_count;
7475         ip = (unsigned char*)header->code;
7476         cfg->cil_start = ip;
7477         end = ip + header->code_size;
7478         cfg->stat_cil_code_size += header->code_size;
7479
7480         seq_points = cfg->gen_seq_points && cfg->method == method;
7481
7482         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
7483                 /* We could hit a seq point before attaching to the JIT (#8338) */
7484                 seq_points = FALSE;
7485         }
7486
7487         if (cfg->gen_sdb_seq_points && cfg->method == method) {
7488                 minfo = mono_debug_lookup_method (method);
7489                 if (minfo) {
7490                         MonoSymSeqPoint *sps;
7491                         int i, n_il_offsets;
7492
7493                         mono_debug_get_seq_points (minfo, NULL, NULL, NULL, &sps, &n_il_offsets);
7494                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7495                         seq_point_set_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7496                         sym_seq_points = TRUE;
7497                         for (i = 0; i < n_il_offsets; ++i) {
7498                                 if (sps [i].il_offset < header->code_size)
7499                                         mono_bitset_set_fast (seq_point_locs, sps [i].il_offset);
7500                         }
7501                         g_free (sps);
7502                 } else if (!method->wrapper_type && !method->dynamic && mono_debug_image_has_debug_info (method->klass->image)) {
7503                         /* Methods without line number info like auto-generated property accessors */
7504                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7505                         seq_point_set_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7506                         sym_seq_points = TRUE;
7507                 }
7508         }
7509
7510         /* 
7511          * Methods without init_locals set could cause asserts in various passes
7512          * (#497220). To work around this, we emit dummy initialization opcodes
7513          * (OP_DUMMY_ICONST etc.) which generate no code. These are only supported
7514          * on some platforms.
7515          */
7516         if ((cfg->opt & MONO_OPT_UNSAFE) && cfg->backend->have_dummy_init)
7517                 init_locals = header->init_locals;
7518         else
7519                 init_locals = TRUE;
7520
7521         method_definition = method;
7522         while (method_definition->is_inflated) {
7523                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
7524                 method_definition = imethod->declaring;
7525         }
7526
7527         /* SkipVerification is not allowed if core-clr is enabled */
7528         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
7529                 dont_verify = TRUE;
7530                 dont_verify_stloc = TRUE;
7531         }
7532
7533         if (sig->is_inflated)
7534                 generic_context = mono_method_get_context (method);
7535         else if (generic_container)
7536                 generic_context = &generic_container->context;
7537         cfg->generic_context = generic_context;
7538
7539         if (!cfg->gshared)
7540                 g_assert (!sig->has_type_parameters);
7541
7542         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
7543                 g_assert (method->is_inflated);
7544                 g_assert (mono_method_get_context (method)->method_inst);
7545         }
7546         if (method->is_inflated && mono_method_get_context (method)->method_inst)
7547                 g_assert (sig->generic_param_count);
7548
7549         if (cfg->method == method) {
7550                 cfg->real_offset = 0;
7551         } else {
7552                 cfg->real_offset = inline_offset;
7553         }
7554
7555         cfg->cil_offset_to_bb = (MonoBasicBlock **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
7556         cfg->cil_offset_to_bb_len = header->code_size;
7557
7558         cfg->current_method = method;
7559
7560         if (cfg->verbose_level > 2)
7561                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
7562
7563         param_types = (MonoType **)mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
7564         if (sig->hasthis)
7565                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
7566         for (n = 0; n < sig->param_count; ++n)
7567                 param_types [n + sig->hasthis] = sig->params [n];
7568         cfg->arg_types = param_types;
7569
7570         cfg->dont_inline = g_list_prepend (cfg->dont_inline, method);
7571         if (cfg->method == method) {
7572
7573                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
7574                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
7575
7576                 /* ENTRY BLOCK */
7577                 NEW_BBLOCK (cfg, start_bblock);
7578                 cfg->bb_entry = start_bblock;
7579                 start_bblock->cil_code = NULL;
7580                 start_bblock->cil_length = 0;
7581
7582                 /* EXIT BLOCK */
7583                 NEW_BBLOCK (cfg, end_bblock);
7584                 cfg->bb_exit = end_bblock;
7585                 end_bblock->cil_code = NULL;
7586                 end_bblock->cil_length = 0;
7587                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
7588                 g_assert (cfg->num_bblocks == 2);
7589
7590                 arg_array = cfg->args;
7591
7592                 if (header->num_clauses) {
7593                         cfg->spvars = g_hash_table_new (NULL, NULL);
7594                         cfg->exvars = g_hash_table_new (NULL, NULL);
7595                 }
7596                 /* handle exception clauses */
7597                 for (i = 0; i < header->num_clauses; ++i) {
7598                         MonoBasicBlock *try_bb;
7599                         MonoExceptionClause *clause = &header->clauses [i];
7600                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
7601
7602                         try_bb->real_offset = clause->try_offset;
7603                         try_bb->try_start = TRUE;
7604                         try_bb->region = ((i + 1) << 8) | clause->flags;
7605                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
7606                         tblock->real_offset = clause->handler_offset;
7607                         tblock->flags |= BB_EXCEPTION_HANDLER;
7608
7609                         /*
7610                          * Linking the try block with the EH block hinders inlining as we won't be able to 
7611                          * merge the bblocks from inlining and produce an artificial hole for no good reason.
7612                          */
7613                         if (COMPILE_LLVM (cfg))
7614                                 link_bblock (cfg, try_bb, tblock);
7615
7616                         if (*(ip + clause->handler_offset) == CEE_POP)
7617                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
7618
7619                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
7620                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
7621                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
7622                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
7623                                 MONO_ADD_INS (tblock, ins);
7624
7625                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FILTER) {
7626                                         /* finally clauses already have a seq point */
7627                                         /* seq points for filter clauses are emitted below */
7628                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
7629                                         MONO_ADD_INS (tblock, ins);
7630                                 }
7631
7632                                 /* todo: is a fault block unsafe to optimize? */
7633                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
7634                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
7635                         }
7636
7637                         /*printf ("clause try IL_%04x to IL_%04x handler %d at IL_%04x to IL_%04x\n", clause->try_offset, clause->try_offset + clause->try_len, clause->flags, clause->handler_offset, clause->handler_offset + clause->handler_len);
7638                           while (p < end) {
7639                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
7640                           }*/
7641                         /* catch and filter blocks get the exception object on the stack */
7642                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
7643                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7644
7645                                 /* mostly like handle_stack_args (), but just sets the input args */
7646                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
7647                                 tblock->in_scount = 1;
7648                                 tblock->in_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7649                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7650
7651                                 cfg->cbb = tblock;
7652
7653 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
7654                                 /* The EH code passes in the exception in a register to both JITted and LLVM compiled code */
7655                                 if (!cfg->compile_llvm) {
7656                                         MONO_INST_NEW (cfg, ins, OP_GET_EX_OBJ);
7657                                         ins->dreg = tblock->in_stack [0]->dreg;
7658                                         MONO_ADD_INS (tblock, ins);
7659                                 }
7660 #else
7661                                 MonoInst *dummy_use;
7662
7663                                 /* 
7664                                  * Add a dummy use for the exvar so its liveness info will be
7665                                  * correct.
7666                                  */
7667                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
7668 #endif
7669
7670                                 if (seq_points && clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7671                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
7672                                         MONO_ADD_INS (tblock, ins);
7673                                 }
7674                                 
7675                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7676                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
7677                                         tblock->flags |= BB_EXCEPTION_HANDLER;
7678                                         tblock->real_offset = clause->data.filter_offset;
7679                                         tblock->in_scount = 1;
7680                                         tblock->in_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7681                                         /* The filter block shares the exvar with the handler block */
7682                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7683                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
7684                                         MONO_ADD_INS (tblock, ins);
7685                                 }
7686                         }
7687
7688                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
7689                                         clause->data.catch_class &&
7690                                         cfg->gshared &&
7691                                         mono_class_check_context_used (clause->data.catch_class)) {
7692                                 /*
7693                                  * In shared generic code with catch
7694                                  * clauses containing type variables
7695                                  * the exception handling code has to
7696                                  * be able to get to the rgctx.
7697                                  * Therefore we have to make sure that
7698                                  * the vtable/mrgctx argument (for
7699                                  * static or generic methods) or the
7700                                  * "this" argument (for non-static
7701                                  * methods) are live.
7702                                  */
7703                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
7704                                                 mini_method_get_context (method)->method_inst ||
7705                                                 method->klass->valuetype) {
7706                                         mono_get_vtable_var (cfg);
7707                                 } else {
7708                                         MonoInst *dummy_use;
7709
7710                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
7711                                 }
7712                         }
7713                 }
7714         } else {
7715                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
7716                 cfg->cbb = start_bblock;
7717                 cfg->args = arg_array;
7718                 mono_save_args (cfg, sig, inline_args);
7719         }
7720
7721         /* FIRST CODE BLOCK */
7722         NEW_BBLOCK (cfg, tblock);
7723         tblock->cil_code = ip;
7724         cfg->cbb = tblock;
7725         cfg->ip = ip;
7726
7727         ADD_BBLOCK (cfg, tblock);
7728
7729         if (cfg->method == method) {
7730                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
7731                 if (breakpoint_id) {
7732                         MONO_INST_NEW (cfg, ins, OP_BREAK);
7733                         MONO_ADD_INS (cfg->cbb, ins);
7734                 }
7735         }
7736
7737         /* we use a separate basic block for the initialization code */
7738         NEW_BBLOCK (cfg, init_localsbb);
7739         if (cfg->method == method)
7740                 cfg->bb_init = init_localsbb;
7741         init_localsbb->real_offset = cfg->real_offset;
7742         start_bblock->next_bb = init_localsbb;
7743         init_localsbb->next_bb = cfg->cbb;
7744         link_bblock (cfg, start_bblock, init_localsbb);
7745         link_bblock (cfg, init_localsbb, cfg->cbb);
7746                 
7747         cfg->cbb = init_localsbb;
7748
7749         if (cfg->gsharedvt && cfg->method == method) {
7750                 MonoGSharedVtMethodInfo *info;
7751                 MonoInst *var, *locals_var;
7752                 int dreg;
7753
7754                 info = (MonoGSharedVtMethodInfo *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
7755                 info->method = cfg->method;
7756                 info->count_entries = 16;
7757                 info->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
7758                 cfg->gsharedvt_info = info;
7759
7760                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
7761                 /* prevent it from being register allocated */
7762                 //var->flags |= MONO_INST_VOLATILE;
7763                 cfg->gsharedvt_info_var = var;
7764
7765                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
7766                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
7767
7768                 /* Allocate locals */
7769                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
7770                 /* prevent it from being register allocated */
7771                 //locals_var->flags |= MONO_INST_VOLATILE;
7772                 cfg->gsharedvt_locals_var = locals_var;
7773
7774                 dreg = alloc_ireg (cfg);
7775                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
7776
7777                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
7778                 ins->dreg = locals_var->dreg;
7779                 ins->sreg1 = dreg;
7780                 MONO_ADD_INS (cfg->cbb, ins);
7781                 cfg->gsharedvt_locals_var_ins = ins;
7782                 
7783                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
7784                 /*
7785                 if (init_locals)
7786                         ins->flags |= MONO_INST_INIT;
7787                 */
7788         }
7789
7790         if (mono_security_core_clr_enabled ()) {
7791                 /* check if this is native code, e.g. an icall or a p/invoke */
7792                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
7793                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
7794                         if (wrapped) {
7795                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
7796                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
7797
7798                                 /* if this ia a native call then it can only be JITted from platform code */
7799                                 if ((icall || pinvk) && method->klass && method->klass->image) {
7800                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
7801                                                 MonoException *ex = icall ? mono_get_exception_security () : 
7802                                                         mono_get_exception_method_access ();
7803                                                 emit_throw_exception (cfg, ex);
7804                                         }
7805                                 }
7806                         }
7807                 }
7808         }
7809
7810         CHECK_CFG_EXCEPTION;
7811
7812         if (header->code_size == 0)
7813                 UNVERIFIED;
7814
7815         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
7816                 ip = err_pos;
7817                 UNVERIFIED;
7818         }
7819
7820         if (cfg->method == method)
7821                 mono_debug_init_method (cfg, cfg->cbb, breakpoint_id);
7822
7823         for (n = 0; n < header->num_locals; ++n) {
7824                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
7825                         UNVERIFIED;
7826         }
7827         class_inits = NULL;
7828
7829         /* We force the vtable variable here for all shared methods
7830            for the possibility that they might show up in a stack
7831            trace where their exact instantiation is needed. */
7832         if (cfg->gshared && method == cfg->method) {
7833                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
7834                                 mini_method_get_context (method)->method_inst ||
7835                                 method->klass->valuetype) {
7836                         mono_get_vtable_var (cfg);
7837                 } else {
7838                         /* FIXME: Is there a better way to do this?
7839                            We need the variable live for the duration
7840                            of the whole method. */
7841                         cfg->args [0]->flags |= MONO_INST_VOLATILE;
7842                 }
7843         }
7844
7845         /* add a check for this != NULL to inlined methods */
7846         if (is_virtual_call) {
7847                 MonoInst *arg_ins;
7848
7849                 NEW_ARGLOAD (cfg, arg_ins, 0);
7850                 MONO_ADD_INS (cfg->cbb, arg_ins);
7851                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
7852         }
7853
7854         skip_dead_blocks = !dont_verify;
7855         if (skip_dead_blocks) {
7856                 original_bb = bb = mono_basic_block_split (method, &cfg->error, header);
7857                 CHECK_CFG_ERROR;
7858                 g_assert (bb);
7859         }
7860
7861         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
7862         stack_start = sp = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
7863
7864         ins_flag = 0;
7865         start_new_bblock = 0;
7866         while (ip < end) {
7867                 if (cfg->method == method)
7868                         cfg->real_offset = ip - header->code;
7869                 else
7870                         cfg->real_offset = inline_offset;
7871                 cfg->ip = ip;
7872
7873                 context_used = 0;
7874
7875                 if (start_new_bblock) {
7876                         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
7877                         if (start_new_bblock == 2) {
7878                                 g_assert (ip == tblock->cil_code);
7879                         } else {
7880                                 GET_BBLOCK (cfg, tblock, ip);
7881                         }
7882                         cfg->cbb->next_bb = tblock;
7883                         cfg->cbb = tblock;
7884                         start_new_bblock = 0;
7885                         for (i = 0; i < cfg->cbb->in_scount; ++i) {
7886                                 if (cfg->verbose_level > 3)
7887                                         printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
7888                                 EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
7889                                 *sp++ = ins;
7890                         }
7891                         if (class_inits)
7892                                 g_slist_free (class_inits);
7893                         class_inits = NULL;
7894                 } else {
7895                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != cfg->cbb)) {
7896                                 link_bblock (cfg, cfg->cbb, tblock);
7897                                 if (sp != stack_start) {
7898                                         handle_stack_args (cfg, stack_start, sp - stack_start);
7899                                         sp = stack_start;
7900                                         CHECK_UNVERIFIABLE (cfg);
7901                                 }
7902                                 cfg->cbb->next_bb = tblock;
7903                                 cfg->cbb = tblock;
7904                                 for (i = 0; i < cfg->cbb->in_scount; ++i) {
7905                                         if (cfg->verbose_level > 3)
7906                                                 printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
7907                                         EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
7908                                         *sp++ = ins;
7909                                 }
7910                                 g_slist_free (class_inits);
7911                                 class_inits = NULL;
7912                         }
7913                 }
7914
7915                 if (skip_dead_blocks) {
7916                         int ip_offset = ip - header->code;
7917
7918                         if (ip_offset == bb->end)
7919                                 bb = bb->next;
7920
7921                         if (bb->dead) {
7922                                 int op_size = mono_opcode_size (ip, end);
7923                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
7924
7925                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
7926
7927                                 if (ip_offset + op_size == bb->end) {
7928                                         MONO_INST_NEW (cfg, ins, OP_NOP);
7929                                         MONO_ADD_INS (cfg->cbb, ins);
7930                                         start_new_bblock = 1;
7931                                 }
7932
7933                                 ip += op_size;
7934                                 continue;
7935                         }
7936                 }
7937                 /*
7938                  * Sequence points are points where the debugger can place a breakpoint.
7939                  * Currently, we generate these automatically at points where the IL
7940                  * stack is empty.
7941                  */
7942                 if (seq_points && ((!sym_seq_points && (sp == stack_start)) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
7943                         /*
7944                          * Make methods interruptable at the beginning, and at the targets of
7945                          * backward branches.
7946                          * Also, do this at the start of every bblock in methods with clauses too,
7947                          * to be able to handle instructions with inprecise control flow like
7948                          * throw/endfinally.
7949                          * Backward branches are handled at the end of method-to-ir ().
7950                          */
7951                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
7952                         gboolean sym_seq_point = sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code);
7953
7954                         /* Avoid sequence points on empty IL like .volatile */
7955                         // FIXME: Enable this
7956                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
7957                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
7958                         if ((sp != stack_start) && !sym_seq_point)
7959                                 ins->flags |= MONO_INST_NONEMPTY_STACK;
7960                         MONO_ADD_INS (cfg->cbb, ins);
7961
7962                         if (sym_seq_points)
7963                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
7964                 }
7965
7966                 cfg->cbb->real_offset = cfg->real_offset;
7967
7968                 if ((cfg->method == method) && cfg->coverage_info) {
7969                         guint32 cil_offset = ip - header->code;
7970                         cfg->coverage_info->data [cil_offset].cil_code = ip;
7971
7972                         /* TODO: Use an increment here */
7973 #if defined(TARGET_X86)
7974                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
7975                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
7976                         ins->inst_imm = 1;
7977                         MONO_ADD_INS (cfg->cbb, ins);
7978 #else
7979                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
7980                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
7981 #endif
7982                 }
7983
7984                 if (cfg->verbose_level > 3)
7985                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
7986
7987                 switch (*ip) {
7988                 case CEE_NOP:
7989                         if (seq_points && !sym_seq_points && sp != stack_start) {
7990                                 /*
7991                                  * The C# compiler uses these nops to notify the JIT that it should
7992                                  * insert seq points.
7993                                  */
7994                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
7995                                 MONO_ADD_INS (cfg->cbb, ins);
7996                         }
7997                         if (cfg->keep_cil_nops)
7998                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
7999                         else
8000                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8001                         ip++;
8002                         MONO_ADD_INS (cfg->cbb, ins);
8003                         break;
8004                 case CEE_BREAK:
8005                         if (should_insert_brekpoint (cfg->method)) {
8006                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
8007                         } else {
8008                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8009                         }
8010                         ip++;
8011                         MONO_ADD_INS (cfg->cbb, ins);
8012                         break;
8013                 case CEE_LDARG_0:
8014                 case CEE_LDARG_1:
8015                 case CEE_LDARG_2:
8016                 case CEE_LDARG_3:
8017                         CHECK_STACK_OVF (1);
8018                         n = (*ip)-CEE_LDARG_0;
8019                         CHECK_ARG (n);
8020                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8021                         ip++;
8022                         *sp++ = ins;
8023                         break;
8024                 case CEE_LDLOC_0:
8025                 case CEE_LDLOC_1:
8026                 case CEE_LDLOC_2:
8027                 case CEE_LDLOC_3:
8028                         CHECK_STACK_OVF (1);
8029                         n = (*ip)-CEE_LDLOC_0;
8030                         CHECK_LOCAL (n);
8031                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8032                         ip++;
8033                         *sp++ = ins;
8034                         break;
8035                 case CEE_STLOC_0:
8036                 case CEE_STLOC_1:
8037                 case CEE_STLOC_2:
8038                 case CEE_STLOC_3: {
8039                         CHECK_STACK (1);
8040                         n = (*ip)-CEE_STLOC_0;
8041                         CHECK_LOCAL (n);
8042                         --sp;
8043                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
8044                                 UNVERIFIED;
8045                         emit_stloc_ir (cfg, sp, header, n);
8046                         ++ip;
8047                         inline_costs += 1;
8048                         break;
8049                         }
8050                 case CEE_LDARG_S:
8051                         CHECK_OPSIZE (2);
8052                         CHECK_STACK_OVF (1);
8053                         n = ip [1];
8054                         CHECK_ARG (n);
8055                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8056                         *sp++ = ins;
8057                         ip += 2;
8058                         break;
8059                 case CEE_LDARGA_S:
8060                         CHECK_OPSIZE (2);
8061                         CHECK_STACK_OVF (1);
8062                         n = ip [1];
8063                         CHECK_ARG (n);
8064                         NEW_ARGLOADA (cfg, ins, n);
8065                         MONO_ADD_INS (cfg->cbb, ins);
8066                         *sp++ = ins;
8067                         ip += 2;
8068                         break;
8069                 case CEE_STARG_S:
8070                         CHECK_OPSIZE (2);
8071                         CHECK_STACK (1);
8072                         --sp;
8073                         n = ip [1];
8074                         CHECK_ARG (n);
8075                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
8076                                 UNVERIFIED;
8077                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
8078                         ip += 2;
8079                         break;
8080                 case CEE_LDLOC_S:
8081                         CHECK_OPSIZE (2);
8082                         CHECK_STACK_OVF (1);
8083                         n = ip [1];
8084                         CHECK_LOCAL (n);
8085                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8086                         *sp++ = ins;
8087                         ip += 2;
8088                         break;
8089                 case CEE_LDLOCA_S: {
8090                         unsigned char *tmp_ip;
8091                         CHECK_OPSIZE (2);
8092                         CHECK_STACK_OVF (1);
8093                         CHECK_LOCAL (ip [1]);
8094
8095                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
8096                                 ip = tmp_ip;
8097                                 inline_costs += 1;
8098                                 break;
8099                         }
8100
8101                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
8102                         *sp++ = ins;
8103                         ip += 2;
8104                         break;
8105                 }
8106                 case CEE_STLOC_S:
8107                         CHECK_OPSIZE (2);
8108                         CHECK_STACK (1);
8109                         --sp;
8110                         CHECK_LOCAL (ip [1]);
8111                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
8112                                 UNVERIFIED;
8113                         emit_stloc_ir (cfg, sp, header, ip [1]);
8114                         ip += 2;
8115                         inline_costs += 1;
8116                         break;
8117                 case CEE_LDNULL:
8118                         CHECK_STACK_OVF (1);
8119                         EMIT_NEW_PCONST (cfg, ins, NULL);
8120                         ins->type = STACK_OBJ;
8121                         ++ip;
8122                         *sp++ = ins;
8123                         break;
8124                 case CEE_LDC_I4_M1:
8125                         CHECK_STACK_OVF (1);
8126                         EMIT_NEW_ICONST (cfg, ins, -1);
8127                         ++ip;
8128                         *sp++ = ins;
8129                         break;
8130                 case CEE_LDC_I4_0:
8131                 case CEE_LDC_I4_1:
8132                 case CEE_LDC_I4_2:
8133                 case CEE_LDC_I4_3:
8134                 case CEE_LDC_I4_4:
8135                 case CEE_LDC_I4_5:
8136                 case CEE_LDC_I4_6:
8137                 case CEE_LDC_I4_7:
8138                 case CEE_LDC_I4_8:
8139                         CHECK_STACK_OVF (1);
8140                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
8141                         ++ip;
8142                         *sp++ = ins;
8143                         break;
8144                 case CEE_LDC_I4_S:
8145                         CHECK_OPSIZE (2);
8146                         CHECK_STACK_OVF (1);
8147                         ++ip;
8148                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
8149                         ++ip;
8150                         *sp++ = ins;
8151                         break;
8152                 case CEE_LDC_I4:
8153                         CHECK_OPSIZE (5);
8154                         CHECK_STACK_OVF (1);
8155                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
8156                         ip += 5;
8157                         *sp++ = ins;
8158                         break;
8159                 case CEE_LDC_I8:
8160                         CHECK_OPSIZE (9);
8161                         CHECK_STACK_OVF (1);
8162                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
8163                         ins->type = STACK_I8;
8164                         ins->dreg = alloc_dreg (cfg, STACK_I8);
8165                         ++ip;
8166                         ins->inst_l = (gint64)read64 (ip);
8167                         MONO_ADD_INS (cfg->cbb, ins);
8168                         ip += 8;
8169                         *sp++ = ins;
8170                         break;
8171                 case CEE_LDC_R4: {
8172                         float *f;
8173                         gboolean use_aotconst = FALSE;
8174
8175 #ifdef TARGET_POWERPC
8176                         /* FIXME: Clean this up */
8177                         if (cfg->compile_aot)
8178                                 use_aotconst = TRUE;
8179 #endif
8180
8181                         /* FIXME: we should really allocate this only late in the compilation process */
8182                         f = (float *)mono_domain_alloc (cfg->domain, sizeof (float));
8183                         CHECK_OPSIZE (5);
8184                         CHECK_STACK_OVF (1);
8185
8186                         if (use_aotconst) {
8187                                 MonoInst *cons;
8188                                 int dreg;
8189
8190                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
8191
8192                                 dreg = alloc_freg (cfg);
8193                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
8194                                 ins->type = cfg->r4_stack_type;
8195                         } else {
8196                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
8197                                 ins->type = cfg->r4_stack_type;
8198                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8199                                 ins->inst_p0 = f;
8200                                 MONO_ADD_INS (cfg->cbb, ins);
8201                         }
8202                         ++ip;
8203                         readr4 (ip, f);
8204                         ip += 4;
8205                         *sp++ = ins;                    
8206                         break;
8207                 }
8208                 case CEE_LDC_R8: {
8209                         double *d;
8210                         gboolean use_aotconst = FALSE;
8211
8212 #ifdef TARGET_POWERPC
8213                         /* FIXME: Clean this up */
8214                         if (cfg->compile_aot)
8215                                 use_aotconst = TRUE;
8216 #endif
8217
8218                         /* FIXME: we should really allocate this only late in the compilation process */
8219                         d = (double *)mono_domain_alloc (cfg->domain, sizeof (double));
8220                         CHECK_OPSIZE (9);
8221                         CHECK_STACK_OVF (1);
8222
8223                         if (use_aotconst) {
8224                                 MonoInst *cons;
8225                                 int dreg;
8226
8227                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
8228
8229                                 dreg = alloc_freg (cfg);
8230                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
8231                                 ins->type = STACK_R8;
8232                         } else {
8233                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
8234                                 ins->type = STACK_R8;
8235                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8236                                 ins->inst_p0 = d;
8237                                 MONO_ADD_INS (cfg->cbb, ins);
8238                         }
8239                         ++ip;
8240                         readr8 (ip, d);
8241                         ip += 8;
8242                         *sp++ = ins;
8243                         break;
8244                 }
8245                 case CEE_DUP: {
8246                         MonoInst *temp, *store;
8247                         CHECK_STACK (1);
8248                         CHECK_STACK_OVF (1);
8249                         sp--;
8250                         ins = *sp;
8251
8252                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
8253                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
8254
8255                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8256                         *sp++ = ins;
8257
8258                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8259                         *sp++ = ins;
8260
8261                         ++ip;
8262                         inline_costs += 2;
8263                         break;
8264                 }
8265                 case CEE_POP:
8266                         CHECK_STACK (1);
8267                         ip++;
8268                         --sp;
8269
8270 #ifdef TARGET_X86
8271                         if (sp [0]->type == STACK_R8)
8272                                 /* we need to pop the value from the x86 FP stack */
8273                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
8274 #endif
8275                         break;
8276                 case CEE_JMP: {
8277                         MonoCallInst *call;
8278                         MonoMethodSignature *fsig;
8279                         int i, n;
8280
8281                         INLINE_FAILURE ("jmp");
8282                         GSHAREDVT_FAILURE (*ip);
8283
8284                         CHECK_OPSIZE (5);
8285                         if (stack_start != sp)
8286                                 UNVERIFIED;
8287                         token = read32 (ip + 1);
8288                         /* FIXME: check the signature matches */
8289                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8290                         CHECK_CFG_ERROR;
8291  
8292                         if (cfg->gshared && mono_method_check_context_used (cmethod))
8293                                 GENERIC_SHARING_FAILURE (CEE_JMP);
8294
8295                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
8296
8297                         fsig = mono_method_signature (cmethod);
8298                         n = fsig->param_count + fsig->hasthis;
8299                         if (cfg->llvm_only) {
8300                                 MonoInst **args;
8301
8302                                 args = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
8303                                 for (i = 0; i < n; ++i)
8304                                         EMIT_NEW_ARGLOAD (cfg, args [i], i);
8305                                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, TRUE, args, NULL, NULL, NULL);
8306                                 /*
8307                                  * The code in mono-basic-block.c treats the rest of the code as dead, but we
8308                                  * have to emit a normal return since llvm expects it.
8309                                  */
8310                                 if (cfg->ret)
8311                                         emit_setret (cfg, ins);
8312                                 MONO_INST_NEW (cfg, ins, OP_BR);
8313                                 ins->inst_target_bb = end_bblock;
8314                                 MONO_ADD_INS (cfg->cbb, ins);
8315                                 link_bblock (cfg, cfg->cbb, end_bblock);
8316                                 ip += 5;
8317                                 break;
8318                         } else if (cfg->backend->have_op_tail_call) {
8319                                 /* Handle tail calls similarly to calls */
8320                                 DISABLE_AOT (cfg);
8321
8322                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
8323                                 call->method = cmethod;
8324                                 call->tail_call = TRUE;
8325                                 call->signature = mono_method_signature (cmethod);
8326                                 call->args = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
8327                                 call->inst.inst_p0 = cmethod;
8328                                 for (i = 0; i < n; ++i)
8329                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
8330
8331                                 if (mini_type_is_vtype (mini_get_underlying_type (call->signature->ret)))
8332                                         call->vret_var = cfg->vret_addr;
8333
8334                                 mono_arch_emit_call (cfg, call);
8335                                 cfg->param_area = MAX(cfg->param_area, call->stack_usage);
8336                                 MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
8337                         } else {
8338                                 for (i = 0; i < num_args; ++i)
8339                                         /* Prevent arguments from being optimized away */
8340                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
8341
8342                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
8343                                 ins = (MonoInst*)call;
8344                                 ins->inst_p0 = cmethod;
8345                                 MONO_ADD_INS (cfg->cbb, ins);
8346                         }
8347
8348                         ip += 5;
8349                         start_new_bblock = 1;
8350                         break;
8351                 }
8352                 case CEE_CALLI: {
8353                         MonoInst *addr;
8354                         MonoMethodSignature *fsig;
8355
8356                         CHECK_OPSIZE (5);
8357                         token = read32 (ip + 1);
8358
8359                         ins = NULL;
8360
8361                         //GSHAREDVT_FAILURE (*ip);
8362                         cmethod = NULL;
8363                         CHECK_STACK (1);
8364                         --sp;
8365                         addr = *sp;
8366                         fsig = mini_get_signature (method, token, generic_context, &cfg->error);
8367                         CHECK_CFG_ERROR;
8368
8369                         if (method->dynamic && fsig->pinvoke) {
8370                                 MonoInst *args [3];
8371
8372                                 /*
8373                                  * This is a call through a function pointer using a pinvoke
8374                                  * signature. Have to create a wrapper and call that instead.
8375                                  * FIXME: This is very slow, need to create a wrapper at JIT time
8376                                  * instead based on the signature.
8377                                  */
8378                                 EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
8379                                 EMIT_NEW_PCONST (cfg, args [1], fsig);
8380                                 args [2] = addr;
8381                                 addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
8382                         }
8383
8384                         n = fsig->param_count + fsig->hasthis;
8385
8386                         CHECK_STACK (n);
8387
8388                         //g_assert (!virtual_ || fsig->hasthis);
8389
8390                         sp -= n;
8391
8392                         inline_costs += 10 * num_calls++;
8393
8394                         /*
8395                          * Making generic calls out of gsharedvt methods.
8396                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
8397                          * patching gshared method addresses into a gsharedvt method.
8398                          */
8399                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
8400                                 /*
8401                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
8402                                  */
8403                                 MonoInst *callee = addr;
8404
8405                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
8406                                         /* Not tested */
8407                                         GSHAREDVT_FAILURE (*ip);
8408
8409                                 if (cfg->llvm_only)
8410                                         // FIXME:
8411                                         GSHAREDVT_FAILURE (*ip);
8412
8413                                 addr = emit_get_rgctx_sig (cfg, context_used,
8414                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
8415                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
8416                                 goto calli_end;
8417                         }
8418
8419                         /* Prevent inlining of methods with indirect calls */
8420                         INLINE_FAILURE ("indirect call");
8421
8422                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
8423                                 MonoJumpInfoType info_type;
8424                                 gpointer info_data;
8425
8426                                 /*
8427                                  * Instead of emitting an indirect call, emit a direct call
8428                                  * with the contents of the aotconst as the patch info.
8429                                  */
8430                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
8431                                         info_type = (MonoJumpInfoType)addr->inst_c1;
8432                                         info_data = addr->inst_p0;
8433                                 } else {
8434                                         info_type = (MonoJumpInfoType)addr->inst_right->inst_c1;
8435                                         info_data = addr->inst_right->inst_left;
8436                                 }
8437
8438                                 if (info_type == MONO_PATCH_INFO_ICALL_ADDR) {
8439                                         ins = (MonoInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_ICALL_ADDR_CALL, info_data, fsig, sp);
8440                                         NULLIFY_INS (addr);
8441                                         goto calli_end;
8442                                 } else if (info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
8443                                         ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
8444                                         NULLIFY_INS (addr);
8445                                         goto calli_end;
8446                                 }
8447                         }
8448                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8449
8450                         calli_end:
8451
8452                         /* End of call, INS should contain the result of the call, if any */
8453
8454                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8455                                 g_assert (ins);
8456                                 *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
8457                         }
8458
8459                         CHECK_CFG_EXCEPTION;
8460
8461                         ip += 5;
8462                         ins_flag = 0;
8463                         constrained_class = NULL;
8464                         break;
8465                 }
8466                 case CEE_CALL:
8467                 case CEE_CALLVIRT: {
8468                         MonoInst *addr = NULL;
8469                         MonoMethodSignature *fsig = NULL;
8470                         int array_rank = 0;
8471                         int virtual_ = *ip == CEE_CALLVIRT;
8472                         gboolean pass_imt_from_rgctx = FALSE;
8473                         MonoInst *imt_arg = NULL;
8474                         MonoInst *keep_this_alive = NULL;
8475                         gboolean pass_vtable = FALSE;
8476                         gboolean pass_mrgctx = FALSE;
8477                         MonoInst *vtable_arg = NULL;
8478                         gboolean check_this = FALSE;
8479                         gboolean supported_tail_call = FALSE;
8480                         gboolean tail_call = FALSE;
8481                         gboolean need_seq_point = FALSE;
8482                         guint32 call_opcode = *ip;
8483                         gboolean emit_widen = TRUE;
8484                         gboolean push_res = TRUE;
8485                         gboolean skip_ret = FALSE;
8486                         gboolean delegate_invoke = FALSE;
8487                         gboolean direct_icall = FALSE;
8488                         gboolean constrained_partial_call = FALSE;
8489                         MonoMethod *cil_method;
8490
8491                         CHECK_OPSIZE (5);
8492                         token = read32 (ip + 1);
8493
8494                         ins = NULL;
8495
8496                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8497                         CHECK_CFG_ERROR;
8498
8499                         cil_method = cmethod;
8500                                 
8501                         if (constrained_class) {
8502                                 if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
8503                                         if (!mini_is_gsharedvt_klass (constrained_class)) {
8504                                                 g_assert (!cmethod->klass->valuetype);
8505                                                 if (!mini_type_is_reference (&constrained_class->byval_arg))
8506                                                         constrained_partial_call = TRUE;
8507                                         }
8508                                 }
8509
8510                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
8511                                         if (cfg->verbose_level > 2)
8512                                                 printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_class));
8513                                         if (!((constrained_class->byval_arg.type == MONO_TYPE_VAR ||
8514                                                    constrained_class->byval_arg.type == MONO_TYPE_MVAR) &&
8515                                                   cfg->gshared)) {
8516                                                 cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_class, generic_context, &cfg->error);
8517                                                 CHECK_CFG_ERROR;
8518                                         }
8519                                 } else {
8520                                         if (cfg->verbose_level > 2)
8521                                                 printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_class));
8522
8523                                         if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
8524                                                 /* 
8525                                                  * This is needed since get_method_constrained can't find 
8526                                                  * the method in klass representing a type var.
8527                                                  * The type var is guaranteed to be a reference type in this
8528                                                  * case.
8529                                                  */
8530                                                 if (!mini_is_gsharedvt_klass (constrained_class))
8531                                                         g_assert (!cmethod->klass->valuetype);
8532                                         } else {
8533                                                 cmethod = mono_get_method_constrained_checked (image, token, constrained_class, generic_context, &cil_method, &cfg->error);
8534                                                 CHECK_CFG_ERROR;
8535                                         }
8536                                 }
8537                         }
8538                                         
8539                         if (!dont_verify && !cfg->skip_visibility) {
8540                                 MonoMethod *target_method = cil_method;
8541                                 if (method->is_inflated) {
8542                                         target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context), &cfg->error);
8543                                         CHECK_CFG_ERROR;
8544                                 }
8545                                 if (!mono_method_can_access_method (method_definition, target_method) &&
8546                                         !mono_method_can_access_method (method, cil_method))
8547                                         emit_method_access_failure (cfg, method, cil_method);
8548                         }
8549
8550                         if (mono_security_core_clr_enabled ())
8551                                 ensure_method_is_allowed_to_call_method (cfg, method, cil_method);
8552
8553                         if (!virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
8554                                 /* MS.NET seems to silently convert this to a callvirt */
8555                                 virtual_ = 1;
8556
8557                         {
8558                                 /*
8559                                  * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
8560                                  * converts to a callvirt.
8561                                  *
8562                                  * tests/bug-515884.il is an example of this behavior
8563                                  */
8564                                 const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
8565                                 const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
8566                                 if (!virtual_ && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
8567                                         virtual_ = 1;
8568                         }
8569
8570                         if (!cmethod->klass->inited)
8571                                 if (!mono_class_init (cmethod->klass))
8572                                         TYPE_LOAD_ERROR (cmethod->klass);
8573
8574                         fsig = mono_method_signature (cmethod);
8575                         if (!fsig)
8576                                 LOAD_ERROR;
8577                         if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
8578                                 mini_class_is_system_array (cmethod->klass)) {
8579                                 array_rank = cmethod->klass->rank;
8580                         } else if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && icall_is_direct_callable (cfg, cmethod)) {
8581                                 direct_icall = TRUE;
8582                         } else if (fsig->pinvoke) {
8583                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
8584                                 fsig = mono_method_signature (wrapper);
8585                         } else if (constrained_class) {
8586                         } else {
8587                                 fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
8588                                 CHECK_CFG_ERROR;
8589                         }
8590
8591                         if (cfg->llvm_only && !cfg->method->wrapper_type && (!cmethod || cmethod->is_inflated))
8592                                 cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
8593
8594                         /* See code below */
8595                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
8596                                 MonoBasicBlock *tbb;
8597
8598                                 GET_BBLOCK (cfg, tbb, ip + 5);
8599                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
8600                                         /*
8601                                          * We want to extend the try block to cover the call, but we can't do it if the
8602                                          * call is made directly since its followed by an exception check.
8603                                          */
8604                                         direct_icall = FALSE;
8605                                 }
8606                         }
8607
8608                         mono_save_token_info (cfg, image, token, cil_method);
8609
8610                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip + 5 - header->code)))
8611                                 need_seq_point = TRUE;
8612
8613                         /* Don't support calls made using type arguments for now */
8614                         /*
8615                           if (cfg->gsharedvt) {
8616                           if (mini_is_gsharedvt_signature (fsig))
8617                           GSHAREDVT_FAILURE (*ip);
8618                           }
8619                         */
8620
8621                         if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
8622                                 g_assert_not_reached ();
8623
8624                         n = fsig->param_count + fsig->hasthis;
8625
8626                         if (!cfg->gshared && mono_class_is_gtd (cmethod->klass))
8627                                 UNVERIFIED;
8628
8629                         if (!cfg->gshared)
8630                                 g_assert (!mono_method_check_context_used (cmethod));
8631
8632                         CHECK_STACK (n);
8633
8634                         //g_assert (!virtual_ || fsig->hasthis);
8635
8636                         sp -= n;
8637
8638                         /*
8639                          * We have the `constrained.' prefix opcode.
8640                          */
8641                         if (constrained_class) {
8642                                 if (mini_is_gsharedvt_klass (constrained_class)) {
8643                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_class->valuetype && cmethod->klass->valuetype) {
8644                                                 /* The 'Own method' case below */
8645                                         } else if (cmethod->klass->image != mono_defaults.corlib && !mono_class_is_interface (cmethod->klass) && !cmethod->klass->valuetype) {
8646                                                 /* 'The type parameter is instantiated as a reference type' case below. */
8647                                         } else {
8648                                                 ins = handle_constrained_gsharedvt_call (cfg, cmethod, fsig, sp, constrained_class, &emit_widen);
8649                                                 CHECK_CFG_EXCEPTION;
8650                                                 g_assert (ins);
8651                                                 goto call_end;
8652                                         }
8653                                 }
8654
8655                                 if (constrained_partial_call) {
8656                                         gboolean need_box = TRUE;
8657
8658                                         /*
8659                                          * The receiver is a valuetype, but the exact type is not known at compile time. This means the
8660                                          * called method is not known at compile time either. The called method could end up being
8661                                          * one of the methods on the parent classes (object/valuetype/enum), in which case we need
8662                                          * to box the receiver.
8663                                          * A simple solution would be to box always and make a normal virtual call, but that would
8664                                          * be bad performance wise.
8665                                          */
8666                                         if (mono_class_is_interface (cmethod->klass) && mono_class_is_ginst (cmethod->klass)) {
8667                                                 /*
8668                                                  * The parent classes implement no generic interfaces, so the called method will be a vtype method, so no boxing neccessary.
8669                                                  */
8670                                                 need_box = FALSE;
8671                                         }
8672
8673                                         if (!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
8674                                                 /* The called method is not virtual, i.e. Object:GetType (), the receiver is a vtype, has to box */
8675                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8676                                                 ins->klass = constrained_class;
8677                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8678                                                 CHECK_CFG_EXCEPTION;
8679                                         } else if (need_box) {
8680                                                 MonoInst *box_type;
8681                                                 MonoBasicBlock *is_ref_bb, *end_bb;
8682                                                 MonoInst *nonbox_call;
8683
8684                                                 /*
8685                                                  * Determine at runtime whenever the called method is defined on object/valuetype/enum, and emit a boxing call
8686                                                  * if needed.
8687                                                  * FIXME: It is possible to inline the called method in a lot of cases, i.e. for T_INT,
8688                                                  * the no-box case goes to a method in Int32, while the box case goes to a method in Enum.
8689                                                  */
8690                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
8691
8692                                                 NEW_BBLOCK (cfg, is_ref_bb);
8693                                                 NEW_BBLOCK (cfg, end_bb);
8694
8695                                                 box_type = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE);
8696                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, box_type->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
8697                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
8698
8699                                                 /* Non-ref case */
8700                                                 nonbox_call = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8701
8702                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
8703
8704                                                 /* Ref case */
8705                                                 MONO_START_BB (cfg, is_ref_bb);
8706                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8707                                                 ins->klass = constrained_class;
8708                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8709                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8710
8711                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
8712
8713                                                 MONO_START_BB (cfg, end_bb);
8714                                                 cfg->cbb = end_bb;
8715
8716                                                 nonbox_call->dreg = ins->dreg;
8717                                                 goto call_end;
8718                                         } else {
8719                                                 g_assert (mono_class_is_interface (cmethod->klass));
8720                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
8721                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8722                                                 goto call_end;
8723                                         }
8724                                 } else if (constrained_class->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
8725                                         /*
8726                                          * The type parameter is instantiated as a valuetype,
8727                                          * but that type doesn't override the method we're
8728                                          * calling, so we need to box `this'.
8729                                          */
8730                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8731                                         ins->klass = constrained_class;
8732                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8733                                         CHECK_CFG_EXCEPTION;
8734                                 } else if (!constrained_class->valuetype) {
8735                                         int dreg = alloc_ireg_ref (cfg);
8736
8737                                         /*
8738                                          * The type parameter is instantiated as a reference
8739                                          * type.  We have a managed pointer on the stack, so
8740                                          * we need to dereference it here.
8741                                          */
8742                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
8743                                         ins->type = STACK_OBJ;
8744                                         sp [0] = ins;
8745                                 } else {
8746                                         if (cmethod->klass->valuetype) {
8747                                                 /* Own method */
8748                                         } else {
8749                                                 /* Interface method */
8750                                                 int ioffset, slot;
8751
8752                                                 mono_class_setup_vtable (constrained_class);
8753                                                 CHECK_TYPELOAD (constrained_class);
8754                                                 ioffset = mono_class_interface_offset (constrained_class, cmethod->klass);
8755                                                 if (ioffset == -1)
8756                                                         TYPE_LOAD_ERROR (constrained_class);
8757                                                 slot = mono_method_get_vtable_slot (cmethod);
8758                                                 if (slot == -1)
8759                                                         TYPE_LOAD_ERROR (cmethod->klass);
8760                                                 cmethod = constrained_class->vtable [ioffset + slot];
8761
8762                                                 if (cmethod->klass == mono_defaults.enum_class) {
8763                                                         /* Enum implements some interfaces, so treat this as the first case */
8764                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8765                                                         ins->klass = constrained_class;
8766                                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
8767                                                         CHECK_CFG_EXCEPTION;
8768                                                 }
8769                                         }
8770                                         virtual_ = 0;
8771                                 }
8772                                 constrained_class = NULL;
8773                         }
8774
8775                         if (check_call_signature (cfg, fsig, sp))
8776                                 UNVERIFIED;
8777
8778                         if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
8779                                 delegate_invoke = TRUE;
8780
8781                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
8782                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8783                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
8784                                         emit_widen = FALSE;
8785                                 }
8786
8787                                 goto call_end;
8788                         }
8789
8790                         /* 
8791                          * If the callee is a shared method, then its static cctor
8792                          * might not get called after the call was patched.
8793                          */
8794                         if (cfg->gshared && cmethod->klass != method->klass && mono_class_is_ginst (cmethod->klass) && mono_method_is_generic_sharable (cmethod, TRUE) && mono_class_needs_cctor_run (cmethod->klass, method)) {
8795                                 emit_class_init (cfg, cmethod->klass);
8796                                 CHECK_TYPELOAD (cmethod->klass);
8797                         }
8798
8799                         check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
8800
8801                         if (cfg->gshared) {
8802                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
8803
8804                                 context_used = mini_method_check_context_used (cfg, cmethod);
8805
8806                                 if (context_used && mono_class_is_interface (cmethod->klass)) {
8807                                         /* Generic method interface
8808                                            calls are resolved via a
8809                                            helper function and don't
8810                                            need an imt. */
8811                                         if (!cmethod_context || !cmethod_context->method_inst)
8812                                                 pass_imt_from_rgctx = TRUE;
8813                                 }
8814
8815                                 /*
8816                                  * If a shared method calls another
8817                                  * shared method then the caller must
8818                                  * have a generic sharing context
8819                                  * because the magic trampoline
8820                                  * requires it.  FIXME: We shouldn't
8821                                  * have to force the vtable/mrgctx
8822                                  * variable here.  Instead there
8823                                  * should be a flag in the cfg to
8824                                  * request a generic sharing context.
8825                                  */
8826                                 if (context_used &&
8827                                                 ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
8828                                         mono_get_vtable_var (cfg);
8829                         }
8830
8831                         if (pass_vtable) {
8832                                 if (context_used) {
8833                                         vtable_arg = mini_emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
8834                                 } else {
8835                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
8836
8837                                         CHECK_TYPELOAD (cmethod->klass);
8838                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
8839                                 }
8840                         }
8841
8842                         if (pass_mrgctx) {
8843                                 g_assert (!vtable_arg);
8844
8845                                 if (!cfg->compile_aot) {
8846                                         /* 
8847                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
8848                                          * for type load errors before.
8849                                          */
8850                                         mono_class_setup_vtable (cmethod->klass);
8851                                         CHECK_TYPELOAD (cmethod->klass);
8852                                 }
8853
8854                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
8855
8856                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
8857                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
8858                                          MONO_METHOD_IS_FINAL (cmethod)) &&
8859                                         !mono_class_is_marshalbyref (cmethod->klass)) {
8860                                         if (virtual_)
8861                                                 check_this = TRUE;
8862                                         virtual_ = 0;
8863                                 }
8864                         }
8865
8866                         if (pass_imt_from_rgctx) {
8867                                 g_assert (!pass_vtable);
8868
8869                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
8870                                         cmethod, MONO_RGCTX_INFO_METHOD);
8871                         }
8872
8873                         if (check_this)
8874                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
8875
8876                         /* Calling virtual generic methods */
8877                         if (virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) &&
8878                             !(MONO_METHOD_IS_FINAL (cmethod) && 
8879                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
8880                             fsig->generic_param_count && 
8881                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) &&
8882                                 !cfg->llvm_only) {
8883                                 MonoInst *this_temp, *this_arg_temp, *store;
8884                                 MonoInst *iargs [4];
8885
8886                                 g_assert (fsig->is_inflated);
8887
8888                                 /* Prevent inlining of methods that contain indirect calls */
8889                                 INLINE_FAILURE ("virtual generic call");
8890
8891                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
8892                                         GSHAREDVT_FAILURE (*ip);
8893
8894                                 if (cfg->backend->have_generalized_imt_trampoline && cfg->backend->gshared_supported && cmethod->wrapper_type == MONO_WRAPPER_NONE) {
8895                                         g_assert (!imt_arg);
8896                                         if (!context_used)
8897                                                 g_assert (cmethod->is_inflated);
8898                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
8899                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
8900                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
8901                                 } else {
8902                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
8903                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
8904                                         MONO_ADD_INS (cfg->cbb, store);
8905
8906                                         /* FIXME: This should be a managed pointer */
8907                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8908
8909                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
8910                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
8911                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
8912                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
8913                                         addr = mono_emit_jit_icall (cfg,
8914                                                                                                 mono_helper_compile_generic_method, iargs);
8915
8916                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
8917
8918                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8919                                 }
8920
8921                                 goto call_end;
8922                         }
8923
8924                         /*
8925                          * Implement a workaround for the inherent races involved in locking:
8926                          * Monitor.Enter ()
8927                          * try {
8928                          * } finally {
8929                          *    Monitor.Exit ()
8930                          * }
8931                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
8932                          * try block, the Exit () won't be executed, see:
8933                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
8934                          * To work around this, we extend such try blocks to include the last x bytes
8935                          * of the Monitor.Enter () call.
8936                          */
8937                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
8938                                 MonoBasicBlock *tbb;
8939
8940                                 GET_BBLOCK (cfg, tbb, ip + 5);
8941                                 /* 
8942                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
8943                                  * from Monitor.Enter like ArgumentNullException.
8944                                  */
8945                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
8946                                         /* Mark this bblock as needing to be extended */
8947                                         tbb->extend_try_block = TRUE;
8948                                 }
8949                         }
8950
8951                         /* Conversion to a JIT intrinsic */
8952                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
8953                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8954                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
8955                                         emit_widen = FALSE;
8956                                 }
8957                                 goto call_end;
8958                         }
8959                         CHECK_CFG_ERROR;
8960                         
8961                         /* Inlining */
8962                         if ((cfg->opt & MONO_OPT_INLINE) &&
8963                                 (!virtual_ || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
8964                             mono_method_check_inlining (cfg, cmethod)) {
8965                                 int costs;
8966                                 gboolean always = FALSE;
8967
8968                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
8969                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
8970                                         /* Prevent inlining of methods that call wrappers */
8971                                         INLINE_FAILURE ("wrapper call");
8972                                         cmethod = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
8973                                         always = TRUE;
8974                                 }
8975
8976                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, always);
8977                                 if (costs) {
8978                                         cfg->real_offset += 5;
8979
8980                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8981                                                 /* *sp is already set by inline_method */
8982                                                 sp++;
8983                                                 push_res = FALSE;
8984                                         }
8985
8986                                         inline_costs += costs;
8987
8988                                         goto call_end;
8989                                 }
8990                         }
8991
8992                         /* Tail recursion elimination */
8993                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
8994                                 gboolean has_vtargs = FALSE;
8995                                 int i;
8996
8997                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
8998                                 INLINE_FAILURE ("tail call");
8999
9000                                 /* keep it simple */
9001                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
9002                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
9003                                                 has_vtargs = TRUE;
9004                                 }
9005
9006                                 if (!has_vtargs) {
9007                                         if (need_seq_point) {
9008                                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
9009                                                 need_seq_point = FALSE;
9010                                         }
9011                                         for (i = 0; i < n; ++i)
9012                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9013                                         MONO_INST_NEW (cfg, ins, OP_BR);
9014                                         MONO_ADD_INS (cfg->cbb, ins);
9015                                         tblock = start_bblock->out_bb [0];
9016                                         link_bblock (cfg, cfg->cbb, tblock);
9017                                         ins->inst_target_bb = tblock;
9018                                         start_new_bblock = 1;
9019
9020                                         /* skip the CEE_RET, too */
9021                                         if (ip_in_bb (cfg, cfg->cbb, ip + 5))
9022                                                 skip_ret = TRUE;
9023                                         push_res = FALSE;
9024                                         goto call_end;
9025                                 }
9026                         }
9027
9028                         inline_costs += 10 * num_calls++;
9029
9030                         /*
9031                          * Synchronized wrappers.
9032                          * Its hard to determine where to replace a method with its synchronized
9033                          * wrapper without causing an infinite recursion. The current solution is
9034                          * to add the synchronized wrapper in the trampolines, and to
9035                          * change the called method to a dummy wrapper, and resolve that wrapper
9036                          * to the real method in mono_jit_compile_method ().
9037                          */
9038                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
9039                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
9040                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
9041                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
9042                         }
9043
9044                         /*
9045                          * Making generic calls out of gsharedvt methods.
9046                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9047                          * patching gshared method addresses into a gsharedvt method.
9048                          */
9049                         if (cfg->gsharedvt && (mini_is_gsharedvt_signature (fsig) || cmethod->is_inflated || mono_class_is_ginst (cmethod->klass)) &&
9050                                 !(cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY) &&
9051                                 (!(cfg->llvm_only && virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)))) {
9052                                 MonoRgctxInfoType info_type;
9053
9054                                 if (virtual_) {
9055                                         //if (mono_class_is_interface (cmethod->klass))
9056                                                 //GSHAREDVT_FAILURE (*ip);
9057                                         // disable for possible remoting calls
9058                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
9059                                                 GSHAREDVT_FAILURE (*ip);
9060                                         if (fsig->generic_param_count) {
9061                                                 /* virtual generic call */
9062                                                 g_assert (!imt_arg);
9063                                                 /* Same as the virtual generic case above */
9064                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9065                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9066                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
9067                                                 vtable_arg = NULL;
9068                                         } else if (mono_class_is_interface (cmethod->klass) && !imt_arg) {
9069                                                 /* This can happen when we call a fully instantiated iface method */
9070                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9071                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9072                                                 vtable_arg = NULL;
9073                                         }
9074                                 }
9075
9076                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
9077                                         keep_this_alive = sp [0];
9078
9079                                 if (virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
9080                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
9081                                 else
9082                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
9083                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
9084
9085                                 if (cfg->llvm_only) {
9086                                         // FIXME: Avoid initializing vtable_arg
9087                                         ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
9088                                 } else {
9089                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9090                                 }
9091                                 goto call_end;
9092                         }
9093
9094                         /* Generic sharing */
9095
9096                         /*
9097                          * Use this if the callee is gsharedvt sharable too, since
9098                          * at runtime we might find an instantiation so the call cannot
9099                          * be patched (the 'no_patch' code path in mini-trampolines.c).
9100                          */
9101                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
9102                                 (!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
9103                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
9104                                 (!virtual_ || MONO_METHOD_IS_FINAL (cmethod) ||
9105                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
9106                                 INLINE_FAILURE ("gshared");
9107
9108                                 g_assert (cfg->gshared && cmethod);
9109                                 g_assert (!addr);
9110
9111                                 /*
9112                                  * We are compiling a call to a
9113                                  * generic method from shared code,
9114                                  * which means that we have to look up
9115                                  * the method in the rgctx and do an
9116                                  * indirect call.
9117                                  */
9118                                 if (fsig->hasthis)
9119                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9120
9121                                 if (cfg->llvm_only) {
9122                                         if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig))
9123                                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER);
9124                                         else
9125                                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9126                                         // FIXME: Avoid initializing imt_arg/vtable_arg
9127                                         ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
9128                                 } else {
9129                                         addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9130                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9131                                 }
9132                                 goto call_end;
9133                         }
9134
9135                         /* Direct calls to icalls */
9136                         if (direct_icall) {
9137                                 MonoMethod *wrapper;
9138                                 int costs;
9139
9140                                 /* Inline the wrapper */
9141                                 wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9142
9143                                 costs = inline_method (cfg, wrapper, fsig, sp, ip, cfg->real_offset, TRUE);
9144                                 g_assert (costs > 0);
9145                                 cfg->real_offset += 5;
9146
9147                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9148                                         /* *sp is already set by inline_method */
9149                                         sp++;
9150                                         push_res = FALSE;
9151                                 }
9152
9153                                 inline_costs += costs;
9154
9155                                 goto call_end;
9156                         }
9157                                         
9158                         /* Array methods */
9159                         if (array_rank) {
9160                                 MonoInst *addr;
9161
9162                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
9163                                         MonoInst *val = sp [fsig->param_count];
9164
9165                                         if (val->type == STACK_OBJ) {
9166                                                 MonoInst *iargs [2];
9167
9168                                                 iargs [0] = sp [0];
9169                                                 iargs [1] = val;
9170                                                 
9171                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
9172                                         }
9173                                         
9174                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
9175                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
9176                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !MONO_INS_IS_PCONST_NULL (val))
9177                                                 emit_write_barrier (cfg, addr, val);
9178                                         if (cfg->gen_write_barriers && mini_is_gsharedvt_klass (cmethod->klass))
9179                                                 GSHAREDVT_FAILURE (*ip);
9180                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
9181                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9182
9183                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
9184                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
9185                                         if (!cmethod->klass->element_class->valuetype && !readonly)
9186                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
9187                                         CHECK_TYPELOAD (cmethod->klass);
9188                                         
9189                                         readonly = FALSE;
9190                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9191                                         ins = addr;
9192                                 } else {
9193                                         g_assert_not_reached ();
9194                                 }
9195
9196                                 emit_widen = FALSE;
9197                                 goto call_end;
9198                         }
9199
9200                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual_ ? sp [0] : NULL);
9201                         if (ins)
9202                                 goto call_end;
9203
9204                         /* Tail prefix / tail call optimization */
9205
9206                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
9207                         /* FIXME: runtime generic context pointer for jumps? */
9208                         /* FIXME: handle this for generic sharing eventually */
9209                         if ((ins_flag & MONO_INST_TAILCALL) &&
9210                                 !vtable_arg && !cfg->gshared && is_supported_tail_call (cfg, method, cmethod, fsig, call_opcode))
9211                                 supported_tail_call = TRUE;
9212
9213                         if (supported_tail_call) {
9214                                 MonoCallInst *call;
9215
9216                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9217                                 INLINE_FAILURE ("tail call");
9218
9219                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
9220
9221                                 if (cfg->backend->have_op_tail_call) {
9222                                         /* Handle tail calls similarly to normal calls */
9223                                         tail_call = TRUE;
9224                                 } else {
9225                                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9226
9227                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9228                                         call->tail_call = TRUE;
9229                                         call->method = cmethod;
9230                                         call->signature = mono_method_signature (cmethod);
9231
9232                                         /*
9233                                          * We implement tail calls by storing the actual arguments into the 
9234                                          * argument variables, then emitting a CEE_JMP.
9235                                          */
9236                                         for (i = 0; i < n; ++i) {
9237                                                 /* Prevent argument from being register allocated */
9238                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
9239                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9240                                         }
9241                                         ins = (MonoInst*)call;
9242                                         ins->inst_p0 = cmethod;
9243                                         ins->inst_p1 = arg_array [0];
9244                                         MONO_ADD_INS (cfg->cbb, ins);
9245                                         link_bblock (cfg, cfg->cbb, end_bblock);
9246                                         start_new_bblock = 1;
9247
9248                                         // FIXME: Eliminate unreachable epilogs
9249
9250                                         /*
9251                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9252                                          * only reachable from this call.
9253                                          */
9254                                         GET_BBLOCK (cfg, tblock, ip + 5);
9255                                         if (tblock == cfg->cbb || tblock->in_count == 0)
9256                                                 skip_ret = TRUE;
9257                                         push_res = FALSE;
9258
9259                                         goto call_end;
9260                                 }
9261                         }
9262
9263                         /*
9264                          * Virtual calls in llvm-only mode.
9265                          */
9266                         if (cfg->llvm_only && virtual_ && cmethod && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
9267                                 ins = emit_llvmonly_virtual_call (cfg, cmethod, fsig, context_used, sp);
9268                                 goto call_end;
9269                         }
9270
9271                         /* Common call */
9272                         if (!(cmethod->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
9273                                 INLINE_FAILURE ("call");
9274                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual_ ? sp [0] : NULL,
9275                                                                                           imt_arg, vtable_arg);
9276
9277                         if (tail_call && !cfg->llvm_only) {
9278                                 link_bblock (cfg, cfg->cbb, end_bblock);
9279                                 start_new_bblock = 1;
9280
9281                                 // FIXME: Eliminate unreachable epilogs
9282
9283                                 /*
9284                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9285                                  * only reachable from this call.
9286                                  */
9287                                 GET_BBLOCK (cfg, tblock, ip + 5);
9288                                 if (tblock == cfg->cbb || tblock->in_count == 0)
9289                                         skip_ret = TRUE;
9290                                 push_res = FALSE;
9291                         }
9292
9293                         call_end:
9294
9295                         /* End of call, INS should contain the result of the call, if any */
9296
9297                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
9298                                 g_assert (ins);
9299                                 if (emit_widen)
9300                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
9301                                 else
9302                                         *sp++ = ins;
9303                         }
9304
9305                         if (keep_this_alive) {
9306                                 MonoInst *dummy_use;
9307
9308                                 /* See mono_emit_method_call_full () */
9309                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
9310                         }
9311
9312                         if (cfg->llvm_only && cmethod && method_needs_stack_walk (cfg, cmethod)) {
9313                                 /*
9314                                  * Clang can convert these calls to tail calls which screw up the stack
9315                                  * walk. This happens even when the -fno-optimize-sibling-calls
9316                                  * option is passed to clang.
9317                                  * Work around this by emitting a dummy call.
9318                                  */
9319                                 mono_emit_jit_icall (cfg, mono_dummy_jit_icall, NULL);
9320                         }
9321
9322                         CHECK_CFG_EXCEPTION;
9323
9324                         ip += 5;
9325                         if (skip_ret) {
9326                                 g_assert (*ip == CEE_RET);
9327                                 ip += 1;
9328                         }
9329                         ins_flag = 0;
9330                         constrained_class = NULL;
9331                         if (need_seq_point)
9332                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
9333                         break;
9334                 }
9335                 case CEE_RET:
9336                         if (cfg->method != method) {
9337                                 /* return from inlined method */
9338                                 /* 
9339                                  * If in_count == 0, that means the ret is unreachable due to
9340                                  * being preceeded by a throw. In that case, inline_method () will
9341                                  * handle setting the return value 
9342                                  * (test case: test_0_inline_throw ()).
9343                                  */
9344                                 if (return_var && cfg->cbb->in_count) {
9345                                         MonoType *ret_type = mono_method_signature (method)->ret;
9346
9347                                         MonoInst *store;
9348                                         CHECK_STACK (1);
9349                                         --sp;
9350
9351                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9352                                                 UNVERIFIED;
9353
9354                                         //g_assert (returnvar != -1);
9355                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
9356                                         cfg->ret_var_set = TRUE;
9357                                 } 
9358                         } else {
9359                                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
9360
9361                                 if (cfg->lmf_var && cfg->cbb->in_count && !cfg->llvm_only)
9362                                         emit_pop_lmf (cfg);
9363
9364                                 if (cfg->ret) {
9365                                         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (method)->ret);
9366
9367                                         if (seq_points && !sym_seq_points) {
9368                                                 /* 
9369                                                  * Place a seq point here too even through the IL stack is not
9370                                                  * empty, so a step over on
9371                                                  * call <FOO>
9372                                                  * ret
9373                                                  * will work correctly.
9374                                                  */
9375                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
9376                                                 MONO_ADD_INS (cfg->cbb, ins);
9377                                         }
9378
9379                                         g_assert (!return_var);
9380                                         CHECK_STACK (1);
9381                                         --sp;
9382
9383                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9384                                                 UNVERIFIED;
9385
9386                                         emit_setret (cfg, *sp);
9387                                 }
9388                         }
9389                         if (sp != stack_start)
9390                                 UNVERIFIED;
9391                         MONO_INST_NEW (cfg, ins, OP_BR);
9392                         ip++;
9393                         ins->inst_target_bb = end_bblock;
9394                         MONO_ADD_INS (cfg->cbb, ins);
9395                         link_bblock (cfg, cfg->cbb, end_bblock);
9396                         start_new_bblock = 1;
9397                         break;
9398                 case CEE_BR_S:
9399                         CHECK_OPSIZE (2);
9400                         MONO_INST_NEW (cfg, ins, OP_BR);
9401                         ip++;
9402                         target = ip + 1 + (signed char)(*ip);
9403                         ++ip;
9404                         GET_BBLOCK (cfg, tblock, target);
9405                         link_bblock (cfg, cfg->cbb, tblock);
9406                         ins->inst_target_bb = tblock;
9407                         if (sp != stack_start) {
9408                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9409                                 sp = stack_start;
9410                                 CHECK_UNVERIFIABLE (cfg);
9411                         }
9412                         MONO_ADD_INS (cfg->cbb, ins);
9413                         start_new_bblock = 1;
9414                         inline_costs += BRANCH_COST;
9415                         break;
9416                 case CEE_BEQ_S:
9417                 case CEE_BGE_S:
9418                 case CEE_BGT_S:
9419                 case CEE_BLE_S:
9420                 case CEE_BLT_S:
9421                 case CEE_BNE_UN_S:
9422                 case CEE_BGE_UN_S:
9423                 case CEE_BGT_UN_S:
9424                 case CEE_BLE_UN_S:
9425                 case CEE_BLT_UN_S:
9426                         CHECK_OPSIZE (2);
9427                         CHECK_STACK (2);
9428                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
9429                         ip++;
9430                         target = ip + 1 + *(signed char*)ip;
9431                         ip++;
9432
9433                         ADD_BINCOND (NULL);
9434
9435                         sp = stack_start;
9436                         inline_costs += BRANCH_COST;
9437                         break;
9438                 case CEE_BR:
9439                         CHECK_OPSIZE (5);
9440                         MONO_INST_NEW (cfg, ins, OP_BR);
9441                         ip++;
9442
9443                         target = ip + 4 + (gint32)read32(ip);
9444                         ip += 4;
9445                         GET_BBLOCK (cfg, tblock, target);
9446                         link_bblock (cfg, cfg->cbb, tblock);
9447                         ins->inst_target_bb = tblock;
9448                         if (sp != stack_start) {
9449                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9450                                 sp = stack_start;
9451                                 CHECK_UNVERIFIABLE (cfg);
9452                         }
9453
9454                         MONO_ADD_INS (cfg->cbb, ins);
9455
9456                         start_new_bblock = 1;
9457                         inline_costs += BRANCH_COST;
9458                         break;
9459                 case CEE_BRFALSE_S:
9460                 case CEE_BRTRUE_S:
9461                 case CEE_BRFALSE:
9462                 case CEE_BRTRUE: {
9463                         MonoInst *cmp;
9464                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
9465                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
9466                         guint32 opsize = is_short ? 1 : 4;
9467
9468                         CHECK_OPSIZE (opsize);
9469                         CHECK_STACK (1);
9470                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
9471                                 UNVERIFIED;
9472                         ip ++;
9473                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
9474                         ip += opsize;
9475
9476                         sp--;
9477
9478                         GET_BBLOCK (cfg, tblock, target);
9479                         link_bblock (cfg, cfg->cbb, tblock);
9480                         GET_BBLOCK (cfg, tblock, ip);
9481                         link_bblock (cfg, cfg->cbb, tblock);
9482
9483                         if (sp != stack_start) {
9484                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9485                                 CHECK_UNVERIFIABLE (cfg);
9486                         }
9487
9488                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
9489                         cmp->sreg1 = sp [0]->dreg;
9490                         type_from_op (cfg, cmp, sp [0], NULL);
9491                         CHECK_TYPE (cmp);
9492
9493 #if SIZEOF_REGISTER == 4
9494                         if (cmp->opcode == OP_LCOMPARE_IMM) {
9495                                 /* Convert it to OP_LCOMPARE */
9496                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
9497                                 ins->type = STACK_I8;
9498                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
9499                                 ins->inst_l = 0;
9500                                 MONO_ADD_INS (cfg->cbb, ins);
9501                                 cmp->opcode = OP_LCOMPARE;
9502                                 cmp->sreg2 = ins->dreg;
9503                         }
9504 #endif
9505                         MONO_ADD_INS (cfg->cbb, cmp);
9506
9507                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
9508                         type_from_op (cfg, ins, sp [0], NULL);
9509                         MONO_ADD_INS (cfg->cbb, ins);
9510                         ins->inst_many_bb = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
9511                         GET_BBLOCK (cfg, tblock, target);
9512                         ins->inst_true_bb = tblock;
9513                         GET_BBLOCK (cfg, tblock, ip);
9514                         ins->inst_false_bb = tblock;
9515                         start_new_bblock = 2;
9516
9517                         sp = stack_start;
9518                         inline_costs += BRANCH_COST;
9519                         break;
9520                 }
9521                 case CEE_BEQ:
9522                 case CEE_BGE:
9523                 case CEE_BGT:
9524                 case CEE_BLE:
9525                 case CEE_BLT:
9526                 case CEE_BNE_UN:
9527                 case CEE_BGE_UN:
9528                 case CEE_BGT_UN:
9529                 case CEE_BLE_UN:
9530                 case CEE_BLT_UN:
9531                         CHECK_OPSIZE (5);
9532                         CHECK_STACK (2);
9533                         MONO_INST_NEW (cfg, ins, *ip);
9534                         ip++;
9535                         target = ip + 4 + (gint32)read32(ip);
9536                         ip += 4;
9537
9538                         ADD_BINCOND (NULL);
9539
9540                         sp = stack_start;
9541                         inline_costs += BRANCH_COST;
9542                         break;
9543                 case CEE_SWITCH: {
9544                         MonoInst *src1;
9545                         MonoBasicBlock **targets;
9546                         MonoBasicBlock *default_bblock;
9547                         MonoJumpInfoBBTable *table;
9548                         int offset_reg = alloc_preg (cfg);
9549                         int target_reg = alloc_preg (cfg);
9550                         int table_reg = alloc_preg (cfg);
9551                         int sum_reg = alloc_preg (cfg);
9552                         gboolean use_op_switch;
9553
9554                         CHECK_OPSIZE (5);
9555                         CHECK_STACK (1);
9556                         n = read32 (ip + 1);
9557                         --sp;
9558                         src1 = sp [0];
9559                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
9560                                 UNVERIFIED;
9561
9562                         ip += 5;
9563                         CHECK_OPSIZE (n * sizeof (guint32));
9564                         target = ip + n * sizeof (guint32);
9565
9566                         GET_BBLOCK (cfg, default_bblock, target);
9567                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
9568
9569                         targets = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
9570                         for (i = 0; i < n; ++i) {
9571                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
9572                                 targets [i] = tblock;
9573                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
9574                                 ip += 4;
9575                         }
9576
9577                         if (sp != stack_start) {
9578                                 /* 
9579                                  * Link the current bb with the targets as well, so handle_stack_args
9580                                  * will set their in_stack correctly.
9581                                  */
9582                                 link_bblock (cfg, cfg->cbb, default_bblock);
9583                                 for (i = 0; i < n; ++i)
9584                                         link_bblock (cfg, cfg->cbb, targets [i]);
9585
9586                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9587                                 sp = stack_start;
9588                                 CHECK_UNVERIFIABLE (cfg);
9589
9590                                 /* Undo the links */
9591                                 mono_unlink_bblock (cfg, cfg->cbb, default_bblock);
9592                                 for (i = 0; i < n; ++i)
9593                                         mono_unlink_bblock (cfg, cfg->cbb, targets [i]);
9594                         }
9595
9596                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
9597                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
9598
9599                         for (i = 0; i < n; ++i)
9600                                 link_bblock (cfg, cfg->cbb, targets [i]);
9601
9602                         table = (MonoJumpInfoBBTable *)mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
9603                         table->table = targets;
9604                         table->table_size = n;
9605
9606                         use_op_switch = FALSE;
9607 #ifdef TARGET_ARM
9608                         /* ARM implements SWITCH statements differently */
9609                         /* FIXME: Make it use the generic implementation */
9610                         if (!cfg->compile_aot)
9611                                 use_op_switch = TRUE;
9612 #endif
9613
9614                         if (COMPILE_LLVM (cfg))
9615                                 use_op_switch = TRUE;
9616
9617                         cfg->cbb->has_jump_table = 1;
9618
9619                         if (use_op_switch) {
9620                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
9621                                 ins->sreg1 = src1->dreg;
9622                                 ins->inst_p0 = table;
9623                                 ins->inst_many_bb = targets;
9624                                 ins->klass = (MonoClass *)GUINT_TO_POINTER (n);
9625                                 MONO_ADD_INS (cfg->cbb, ins);
9626                         } else {
9627                                 if (sizeof (gpointer) == 8)
9628                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
9629                                 else
9630                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
9631
9632 #if SIZEOF_REGISTER == 8
9633                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
9634                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
9635 #endif
9636
9637                                 if (cfg->compile_aot) {
9638                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
9639                                 } else {
9640                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
9641                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
9642                                         ins->inst_p0 = table;
9643                                         ins->dreg = table_reg;
9644                                         MONO_ADD_INS (cfg->cbb, ins);
9645                                 }
9646
9647                                 /* FIXME: Use load_memindex */
9648                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
9649                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
9650                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
9651                         }
9652                         start_new_bblock = 1;
9653                         inline_costs += (BRANCH_COST * 2);
9654                         break;
9655                 }
9656                 case CEE_LDIND_I1:
9657                 case CEE_LDIND_U1:
9658                 case CEE_LDIND_I2:
9659                 case CEE_LDIND_U2:
9660                 case CEE_LDIND_I4:
9661                 case CEE_LDIND_U4:
9662                 case CEE_LDIND_I8:
9663                 case CEE_LDIND_I:
9664                 case CEE_LDIND_R4:
9665                 case CEE_LDIND_R8:
9666                 case CEE_LDIND_REF:
9667                         CHECK_STACK (1);
9668                         --sp;
9669
9670                         switch (*ip) {
9671                         case CEE_LDIND_R4:
9672                         case CEE_LDIND_R8:
9673                                 dreg = alloc_freg (cfg);
9674                                 break;
9675                         case CEE_LDIND_I8:
9676                                 dreg = alloc_lreg (cfg);
9677                                 break;
9678                         case CEE_LDIND_REF:
9679                                 dreg = alloc_ireg_ref (cfg);
9680                                 break;
9681                         default:
9682                                 dreg = alloc_preg (cfg);
9683                         }
9684
9685                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
9686                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
9687                         if (*ip == CEE_LDIND_R4)
9688                                 ins->type = cfg->r4_stack_type;
9689                         ins->flags |= ins_flag;
9690                         MONO_ADD_INS (cfg->cbb, ins);
9691                         *sp++ = ins;
9692                         if (ins_flag & MONO_INST_VOLATILE) {
9693                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
9694                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
9695                         }
9696                         ins_flag = 0;
9697                         ++ip;
9698                         break;
9699                 case CEE_STIND_REF:
9700                 case CEE_STIND_I1:
9701                 case CEE_STIND_I2:
9702                 case CEE_STIND_I4:
9703                 case CEE_STIND_I8:
9704                 case CEE_STIND_R4:
9705                 case CEE_STIND_R8:
9706                 case CEE_STIND_I:
9707                         CHECK_STACK (2);
9708                         sp -= 2;
9709
9710                         if (ins_flag & MONO_INST_VOLATILE) {
9711                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
9712                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
9713                         }
9714
9715                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
9716                         ins->flags |= ins_flag;
9717                         ins_flag = 0;
9718
9719                         MONO_ADD_INS (cfg->cbb, ins);
9720
9721                         if (cfg->gen_write_barriers && *ip == CEE_STIND_REF && method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER && !MONO_INS_IS_PCONST_NULL (sp [1]))
9722                                 emit_write_barrier (cfg, sp [0], sp [1]);
9723
9724                         inline_costs += 1;
9725                         ++ip;
9726                         break;
9727
9728                 case CEE_MUL:
9729                         CHECK_STACK (2);
9730
9731                         MONO_INST_NEW (cfg, ins, (*ip));
9732                         sp -= 2;
9733                         ins->sreg1 = sp [0]->dreg;
9734                         ins->sreg2 = sp [1]->dreg;
9735                         type_from_op (cfg, ins, sp [0], sp [1]);
9736                         CHECK_TYPE (ins);
9737                         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type);
9738
9739                         /* Use the immediate opcodes if possible */
9740                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
9741                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
9742                                 if (imm_opcode != -1) {
9743                                         ins->opcode = imm_opcode;
9744                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
9745                                         ins->sreg2 = -1;
9746
9747                                         NULLIFY_INS (sp [1]);
9748                                 }
9749                         }
9750
9751                         MONO_ADD_INS ((cfg)->cbb, (ins));
9752
9753                         *sp++ = mono_decompose_opcode (cfg, ins);
9754                         ip++;
9755                         break;
9756                 case CEE_ADD:
9757                 case CEE_SUB:
9758                 case CEE_DIV:
9759                 case CEE_DIV_UN:
9760                 case CEE_REM:
9761                 case CEE_REM_UN:
9762                 case CEE_AND:
9763                 case CEE_OR:
9764                 case CEE_XOR:
9765                 case CEE_SHL:
9766                 case CEE_SHR:
9767                 case CEE_SHR_UN:
9768                         CHECK_STACK (2);
9769
9770                         MONO_INST_NEW (cfg, ins, (*ip));
9771                         sp -= 2;
9772                         ins->sreg1 = sp [0]->dreg;
9773                         ins->sreg2 = sp [1]->dreg;
9774                         type_from_op (cfg, ins, sp [0], sp [1]);
9775                         CHECK_TYPE (ins);
9776                         add_widen_op (cfg, ins, &sp [0], &sp [1]);
9777                         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type);
9778
9779                         /* FIXME: Pass opcode to is_inst_imm */
9780
9781                         /* Use the immediate opcodes if possible */
9782                         if (((sp [1]->opcode == OP_ICONST) || (sp [1]->opcode == OP_I8CONST)) && mono_arch_is_inst_imm (sp [1]->opcode == OP_ICONST ? sp [1]->inst_c0 : sp [1]->inst_l)) {
9783                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
9784                                 if (imm_opcode != -1) {
9785                                         ins->opcode = imm_opcode;
9786                                         if (sp [1]->opcode == OP_I8CONST) {
9787 #if SIZEOF_REGISTER == 8
9788                                                 ins->inst_imm = sp [1]->inst_l;
9789 #else
9790                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
9791                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
9792 #endif
9793                                         }
9794                                         else
9795                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
9796                                         ins->sreg2 = -1;
9797
9798                                         /* Might be followed by an instruction added by add_widen_op */
9799                                         if (sp [1]->next == NULL)
9800                                                 NULLIFY_INS (sp [1]);
9801                                 }
9802                         }
9803                         MONO_ADD_INS ((cfg)->cbb, (ins));
9804
9805                         *sp++ = mono_decompose_opcode (cfg, ins);
9806                         ip++;
9807                         break;
9808                 case CEE_NEG:
9809                 case CEE_NOT:
9810                 case CEE_CONV_I1:
9811                 case CEE_CONV_I2:
9812                 case CEE_CONV_I4:
9813                 case CEE_CONV_R4:
9814                 case CEE_CONV_R8:
9815                 case CEE_CONV_U4:
9816                 case CEE_CONV_I8:
9817                 case CEE_CONV_U8:
9818                 case CEE_CONV_OVF_I8:
9819                 case CEE_CONV_OVF_U8:
9820                 case CEE_CONV_R_UN:
9821                         CHECK_STACK (1);
9822
9823                         /* Special case this earlier so we have long constants in the IR */
9824                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
9825                                 int data = sp [-1]->inst_c0;
9826                                 sp [-1]->opcode = OP_I8CONST;
9827                                 sp [-1]->type = STACK_I8;
9828 #if SIZEOF_REGISTER == 8
9829                                 if ((*ip) == CEE_CONV_U8)
9830                                         sp [-1]->inst_c0 = (guint32)data;
9831                                 else
9832                                         sp [-1]->inst_c0 = data;
9833 #else
9834                                 sp [-1]->inst_ls_word = data;
9835                                 if ((*ip) == CEE_CONV_U8)
9836                                         sp [-1]->inst_ms_word = 0;
9837                                 else
9838                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
9839 #endif
9840                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
9841                         }
9842                         else {
9843                                 ADD_UNOP (*ip);
9844                         }
9845                         ip++;
9846                         break;
9847                 case CEE_CONV_OVF_I4:
9848                 case CEE_CONV_OVF_I1:
9849                 case CEE_CONV_OVF_I2:
9850                 case CEE_CONV_OVF_I:
9851                 case CEE_CONV_OVF_U:
9852                         CHECK_STACK (1);
9853
9854                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
9855                                 ADD_UNOP (CEE_CONV_OVF_I8);
9856                                 ADD_UNOP (*ip);
9857                         } else {
9858                                 ADD_UNOP (*ip);
9859                         }
9860                         ip++;
9861                         break;
9862                 case CEE_CONV_OVF_U1:
9863                 case CEE_CONV_OVF_U2:
9864                 case CEE_CONV_OVF_U4:
9865                         CHECK_STACK (1);
9866
9867                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
9868                                 ADD_UNOP (CEE_CONV_OVF_U8);
9869                                 ADD_UNOP (*ip);
9870                         } else {
9871                                 ADD_UNOP (*ip);
9872                         }
9873                         ip++;
9874                         break;
9875                 case CEE_CONV_OVF_I1_UN:
9876                 case CEE_CONV_OVF_I2_UN:
9877                 case CEE_CONV_OVF_I4_UN:
9878                 case CEE_CONV_OVF_I8_UN:
9879                 case CEE_CONV_OVF_U1_UN:
9880                 case CEE_CONV_OVF_U2_UN:
9881                 case CEE_CONV_OVF_U4_UN:
9882                 case CEE_CONV_OVF_U8_UN:
9883                 case CEE_CONV_OVF_I_UN:
9884                 case CEE_CONV_OVF_U_UN:
9885                 case CEE_CONV_U2:
9886                 case CEE_CONV_U1:
9887                 case CEE_CONV_I:
9888                 case CEE_CONV_U:
9889                         CHECK_STACK (1);
9890                         ADD_UNOP (*ip);
9891                         CHECK_CFG_EXCEPTION;
9892                         ip++;
9893                         break;
9894                 case CEE_ADD_OVF:
9895                 case CEE_ADD_OVF_UN:
9896                 case CEE_MUL_OVF:
9897                 case CEE_MUL_OVF_UN:
9898                 case CEE_SUB_OVF:
9899                 case CEE_SUB_OVF_UN:
9900                         CHECK_STACK (2);
9901                         ADD_BINOP (*ip);
9902                         ip++;
9903                         break;
9904                 case CEE_CPOBJ:
9905                         GSHAREDVT_FAILURE (*ip);
9906                         CHECK_OPSIZE (5);
9907                         CHECK_STACK (2);
9908                         token = read32 (ip + 1);
9909                         klass = mini_get_class (method, token, generic_context);
9910                         CHECK_TYPELOAD (klass);
9911                         sp -= 2;
9912                         if (generic_class_is_reference_type (cfg, klass)) {
9913                                 MonoInst *store, *load;
9914                                 int dreg = alloc_ireg_ref (cfg);
9915
9916                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
9917                                 load->flags |= ins_flag;
9918                                 MONO_ADD_INS (cfg->cbb, load);
9919
9920                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
9921                                 store->flags |= ins_flag;
9922                                 MONO_ADD_INS (cfg->cbb, store);
9923
9924                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
9925                                         emit_write_barrier (cfg, sp [0], sp [1]);
9926                         } else {
9927                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
9928                         }
9929                         ins_flag = 0;
9930                         ip += 5;
9931                         break;
9932                 case CEE_LDOBJ: {
9933                         int loc_index = -1;
9934                         int stloc_len = 0;
9935
9936                         CHECK_OPSIZE (5);
9937                         CHECK_STACK (1);
9938                         --sp;
9939                         token = read32 (ip + 1);
9940                         klass = mini_get_class (method, token, generic_context);
9941                         CHECK_TYPELOAD (klass);
9942
9943                         /* Optimize the common ldobj+stloc combination */
9944                         switch (ip [5]) {
9945                         case CEE_STLOC_S:
9946                                 loc_index = ip [6];
9947                                 stloc_len = 2;
9948                                 break;
9949                         case CEE_STLOC_0:
9950                         case CEE_STLOC_1:
9951                         case CEE_STLOC_2:
9952                         case CEE_STLOC_3:
9953                                 loc_index = ip [5] - CEE_STLOC_0;
9954                                 stloc_len = 1;
9955                                 break;
9956                         default:
9957                                 break;
9958                         }
9959
9960                         if ((loc_index != -1) && ip_in_bb (cfg, cfg->cbb, ip + 5)) {
9961                                 CHECK_LOCAL (loc_index);
9962
9963                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
9964                                 ins->dreg = cfg->locals [loc_index]->dreg;
9965                                 ins->flags |= ins_flag;
9966                                 ip += 5;
9967                                 ip += stloc_len;
9968                                 if (ins_flag & MONO_INST_VOLATILE) {
9969                                         /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
9970                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
9971                                 }
9972                                 ins_flag = 0;
9973                                 break;
9974                         }
9975
9976                         /* Optimize the ldobj+stobj combination */
9977                         /* The reference case ends up being a load+store anyway */
9978                         /* Skip this if the operation is volatile. */
9979                         if (((ip [5] == CEE_STOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 5) && read32 (ip + 6) == token) && !generic_class_is_reference_type (cfg, klass) && !(ins_flag & MONO_INST_VOLATILE)) {
9980                                 CHECK_STACK (1);
9981
9982                                 sp --;
9983
9984                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
9985
9986                                 ip += 5 + 5;
9987                                 ins_flag = 0;
9988                                 break;
9989                         }
9990
9991                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
9992                         ins->flags |= ins_flag;
9993                         *sp++ = ins;
9994
9995                         if (ins_flag & MONO_INST_VOLATILE) {
9996                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
9997                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
9998                         }
9999
10000                         ip += 5;
10001                         ins_flag = 0;
10002                         inline_costs += 1;
10003                         break;
10004                 }
10005                 case CEE_LDSTR:
10006                         CHECK_STACK_OVF (1);
10007                         CHECK_OPSIZE (5);
10008                         n = read32 (ip + 1);
10009
10010                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
10011                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
10012                                 ins->type = STACK_OBJ;
10013                                 *sp = ins;
10014                         }
10015                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
10016                                 MonoInst *iargs [1];
10017                                 char *str = (char *)mono_method_get_wrapper_data (method, n);
10018
10019                                 if (cfg->compile_aot)
10020                                         EMIT_NEW_LDSTRLITCONST (cfg, iargs [0], str);
10021                                 else
10022                                         EMIT_NEW_PCONST (cfg, iargs [0], str);
10023                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
10024                         } else {
10025                                 if (cfg->opt & MONO_OPT_SHARED) {
10026                                         MonoInst *iargs [3];
10027
10028                                         if (cfg->compile_aot) {
10029                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
10030                                         }
10031                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10032                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
10033                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
10034                                         *sp = mono_emit_jit_icall (cfg, ves_icall_mono_ldstr, iargs);
10035                                         mono_ldstr_checked (cfg->domain, image, mono_metadata_token_index (n), &cfg->error);
10036                                         CHECK_CFG_ERROR;
10037                                 } else {
10038                                         if (cfg->cbb->out_of_line) {
10039                                                 MonoInst *iargs [2];
10040
10041                                                 if (image == mono_defaults.corlib) {
10042                                                         /* 
10043                                                          * Avoid relocations in AOT and save some space by using a 
10044                                                          * version of helper_ldstr specialized to mscorlib.
10045                                                          */
10046                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
10047                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
10048                                                 } else {
10049                                                         /* Avoid creating the string object */
10050                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
10051                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
10052                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
10053                                                 }
10054                                         } 
10055                                         else
10056                                         if (cfg->compile_aot) {
10057                                                 NEW_LDSTRCONST (cfg, ins, image, n);
10058                                                 *sp = ins;
10059                                                 MONO_ADD_INS (cfg->cbb, ins);
10060                                         } 
10061                                         else {
10062                                                 NEW_PCONST (cfg, ins, NULL);
10063                                                 ins->type = STACK_OBJ;
10064                                                 ins->inst_p0 = mono_ldstr_checked (cfg->domain, image, mono_metadata_token_index (n), &cfg->error);
10065                                                 CHECK_CFG_ERROR;
10066                                                 
10067                                                 if (!ins->inst_p0)
10068                                                         OUT_OF_MEMORY_FAILURE;
10069
10070                                                 *sp = ins;
10071                                                 MONO_ADD_INS (cfg->cbb, ins);
10072                                         }
10073                                 }
10074                         }
10075
10076                         sp++;
10077                         ip += 5;
10078                         break;
10079                 case CEE_NEWOBJ: {
10080                         MonoInst *iargs [2];
10081                         MonoMethodSignature *fsig;
10082                         MonoInst this_ins;
10083                         MonoInst *alloc;
10084                         MonoInst *vtable_arg = NULL;
10085
10086                         CHECK_OPSIZE (5);
10087                         token = read32 (ip + 1);
10088                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
10089                         CHECK_CFG_ERROR;
10090
10091                         fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
10092                         CHECK_CFG_ERROR;
10093
10094                         mono_save_token_info (cfg, image, token, cmethod);
10095
10096                         if (!mono_class_init (cmethod->klass))
10097                                 TYPE_LOAD_ERROR (cmethod->klass);
10098
10099                         context_used = mini_method_check_context_used (cfg, cmethod);
10100
10101                         if (mono_security_core_clr_enabled ())
10102                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
10103
10104                         if (cfg->gshared && cmethod && cmethod->klass != method->klass && mono_class_is_ginst (cmethod->klass) && mono_method_is_generic_sharable (cmethod, TRUE) && mono_class_needs_cctor_run (cmethod->klass, method)) {
10105                                 emit_class_init (cfg, cmethod->klass);
10106                                 CHECK_TYPELOAD (cmethod->klass);
10107                         }
10108
10109                         /*
10110                         if (cfg->gsharedvt) {
10111                                 if (mini_is_gsharedvt_variable_signature (sig))
10112                                         GSHAREDVT_FAILURE (*ip);
10113                         }
10114                         */
10115
10116                         n = fsig->param_count;
10117                         CHECK_STACK (n);
10118
10119                         /* 
10120                          * Generate smaller code for the common newobj <exception> instruction in
10121                          * argument checking code.
10122                          */
10123                         if (cfg->cbb->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
10124                                 is_exception_class (cmethod->klass) && n <= 2 &&
10125                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
10126                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
10127                                 MonoInst *iargs [3];
10128
10129                                 sp -= n;
10130
10131                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
10132                                 switch (n) {
10133                                 case 0:
10134                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
10135                                         break;
10136                                 case 1:
10137                                         iargs [1] = sp [0];
10138                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
10139                                         break;
10140                                 case 2:
10141                                         iargs [1] = sp [0];
10142                                         iargs [2] = sp [1];
10143                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
10144                                         break;
10145                                 default:
10146                                         g_assert_not_reached ();
10147                                 }
10148
10149                                 ip += 5;
10150                                 inline_costs += 5;
10151                                 break;
10152                         }
10153
10154                         /* move the args to allow room for 'this' in the first position */
10155                         while (n--) {
10156                                 --sp;
10157                                 sp [1] = sp [0];
10158                         }
10159
10160                         /* check_call_signature () requires sp[0] to be set */
10161                         this_ins.type = STACK_OBJ;
10162                         sp [0] = &this_ins;
10163                         if (check_call_signature (cfg, fsig, sp))
10164                                 UNVERIFIED;
10165
10166                         iargs [0] = NULL;
10167
10168                         if (mini_class_is_system_array (cmethod->klass)) {
10169                                 *sp = emit_get_rgctx_method (cfg, context_used,
10170                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
10171
10172                                 /* Avoid varargs in the common case */
10173                                 if (fsig->param_count == 1)
10174                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
10175                                 else if (fsig->param_count == 2)
10176                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
10177                                 else if (fsig->param_count == 3)
10178                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
10179                                 else if (fsig->param_count == 4)
10180                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
10181                                 else
10182                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
10183                         } else if (cmethod->string_ctor) {
10184                                 g_assert (!context_used);
10185                                 g_assert (!vtable_arg);
10186                                 /* we simply pass a null pointer */
10187                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
10188                                 /* now call the string ctor */
10189                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
10190                         } else {
10191                                 if (cmethod->klass->valuetype) {
10192                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
10193                                         emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
10194                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
10195
10196                                         alloc = NULL;
10197
10198                                         /* 
10199                                          * The code generated by mini_emit_virtual_call () expects
10200                                          * iargs [0] to be a boxed instance, but luckily the vcall
10201                                          * will be transformed into a normal call there.
10202                                          */
10203                                 } else if (context_used) {
10204                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
10205                                         *sp = alloc;
10206                                 } else {
10207                                         MonoVTable *vtable = NULL;
10208
10209                                         if (!cfg->compile_aot)
10210                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
10211                                         CHECK_TYPELOAD (cmethod->klass);
10212
10213                                         /*
10214                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
10215                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
10216                                          * As a workaround, we call class cctors before allocating objects.
10217                                          */
10218                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
10219                                                 emit_class_init (cfg, cmethod->klass);
10220                                                 if (cfg->verbose_level > 2)
10221                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
10222                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
10223                                         }
10224
10225                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
10226                                         *sp = alloc;
10227                                 }
10228                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
10229
10230                                 if (alloc)
10231                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
10232
10233                                 /* Now call the actual ctor */
10234                                 handle_ctor_call (cfg, cmethod, fsig, context_used, sp, ip, &inline_costs);
10235                                 CHECK_CFG_EXCEPTION;
10236                         }
10237
10238                         if (alloc == NULL) {
10239                                 /* Valuetype */
10240                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
10241                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
10242                                 *sp++= ins;
10243                         } else {
10244                                 *sp++ = alloc;
10245                         }
10246                         
10247                         ip += 5;
10248                         inline_costs += 5;
10249                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip - header->code)))
10250                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10251                         break;
10252                 }
10253                 case CEE_CASTCLASS:
10254                 case CEE_ISINST: {
10255                         CHECK_STACK (1);
10256                         --sp;
10257                         CHECK_OPSIZE (5);
10258                         token = read32 (ip + 1);
10259                         klass = mini_get_class (method, token, generic_context);
10260                         CHECK_TYPELOAD (klass);
10261                         if (sp [0]->type != STACK_OBJ)
10262                                 UNVERIFIED;
10263
10264                         MONO_INST_NEW (cfg, ins, *ip == CEE_ISINST ? OP_ISINST : OP_CASTCLASS);
10265                         ins->dreg = alloc_preg (cfg);
10266                         ins->sreg1 = (*sp)->dreg;
10267                         ins->klass = klass;
10268                         ins->type = STACK_OBJ;
10269                         MONO_ADD_INS (cfg->cbb, ins);
10270
10271                         CHECK_CFG_EXCEPTION;
10272                         *sp++ = ins;
10273                         ip += 5;
10274
10275                         cfg->flags |= MONO_CFG_HAS_TYPE_CHECK;
10276                         break;
10277                 }
10278                 case CEE_UNBOX_ANY: {
10279                         MonoInst *res, *addr;
10280
10281                         CHECK_STACK (1);
10282                         --sp;
10283                         CHECK_OPSIZE (5);
10284                         token = read32 (ip + 1);
10285                         klass = mini_get_class (method, token, generic_context);
10286                         CHECK_TYPELOAD (klass);
10287
10288                         mono_save_token_info (cfg, image, token, klass);
10289
10290                         context_used = mini_class_check_context_used (cfg, klass);
10291
10292                         if (mini_is_gsharedvt_klass (klass)) {
10293                                 res = handle_unbox_gsharedvt (cfg, klass, *sp);
10294                                 inline_costs += 2;
10295                         } else if (generic_class_is_reference_type (cfg, klass)) {
10296                                 if (MONO_INS_IS_PCONST_NULL (*sp)) {
10297                                         EMIT_NEW_PCONST (cfg, res, NULL);
10298                                         res->type = STACK_OBJ;
10299                                 } else {
10300                                         MONO_INST_NEW (cfg, res, OP_CASTCLASS);
10301                                         res->dreg = alloc_preg (cfg);
10302                                         res->sreg1 = (*sp)->dreg;
10303                                         res->klass = klass;
10304                                         res->type = STACK_OBJ;
10305                                         MONO_ADD_INS (cfg->cbb, res);
10306                                         cfg->flags |= MONO_CFG_HAS_TYPE_CHECK;
10307                                 }
10308                         } else if (mono_class_is_nullable (klass)) {
10309                                 res = handle_unbox_nullable (cfg, *sp, klass, context_used);
10310                         } else {
10311                                 addr = handle_unbox (cfg, klass, sp, context_used);
10312                                 /* LDOBJ */
10313                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
10314                                 res = ins;
10315                                 inline_costs += 2;
10316                         }
10317
10318                         *sp ++ = res;
10319                         ip += 5;
10320                         break;
10321                 }
10322                 case CEE_BOX: {
10323                         MonoInst *val;
10324                         MonoClass *enum_class;
10325                         MonoMethod *has_flag;
10326
10327                         CHECK_STACK (1);
10328                         --sp;
10329                         val = *sp;
10330                         CHECK_OPSIZE (5);
10331                         token = read32 (ip + 1);
10332                         klass = mini_get_class (method, token, generic_context);
10333                         CHECK_TYPELOAD (klass);
10334
10335                         mono_save_token_info (cfg, image, token, klass);
10336
10337                         context_used = mini_class_check_context_used (cfg, klass);
10338
10339                         if (generic_class_is_reference_type (cfg, klass)) {
10340                                 *sp++ = val;
10341                                 ip += 5;
10342                                 break;
10343                         }
10344
10345                         if (klass == mono_defaults.void_class)
10346                                 UNVERIFIED;
10347                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
10348                                 UNVERIFIED;
10349                         /* frequent check in generic code: box (struct), brtrue */
10350
10351                         /*
10352                          * Look for:
10353                          *
10354                          *   <push int/long ptr>
10355                          *   <push int/long>
10356                          *   box MyFlags
10357                          *   constrained. MyFlags
10358                          *   callvirt instace bool class [mscorlib] System.Enum::HasFlag (class [mscorlib] System.Enum)
10359                          *
10360                          * If we find this sequence and the operand types on box and constrained
10361                          * are equal, we can emit a specialized instruction sequence instead of
10362                          * the very slow HasFlag () call.
10363                          */
10364                         if ((cfg->opt & MONO_OPT_INTRINS) &&
10365                             /* Cheap checks first. */
10366                             ip + 5 + 6 + 5 < end &&
10367                             ip [5] == CEE_PREFIX1 &&
10368                             ip [6] == CEE_CONSTRAINED_ &&
10369                             ip [11] == CEE_CALLVIRT &&
10370                             ip_in_bb (cfg, cfg->cbb, ip + 5 + 6 + 5) &&
10371                             mono_class_is_enum (klass) &&
10372                             (enum_class = mini_get_class (method, read32 (ip + 7), generic_context)) &&
10373                             (has_flag = mini_get_method (cfg, method, read32 (ip + 12), NULL, generic_context)) &&
10374                             has_flag->klass == mono_defaults.enum_class &&
10375                             !strcmp (has_flag->name, "HasFlag") &&
10376                             has_flag->signature->hasthis &&
10377                             has_flag->signature->param_count == 1) {
10378                                 CHECK_TYPELOAD (enum_class);
10379
10380                                 if (enum_class == klass) {
10381                                         MonoInst *enum_this, *enum_flag;
10382
10383                                         ip += 5 + 6 + 5;
10384                                         --sp;
10385
10386                                         enum_this = sp [0];
10387                                         enum_flag = sp [1];
10388
10389                                         *sp++ = handle_enum_has_flag (cfg, klass, enum_this, enum_flag);
10390                                         break;
10391                                 }
10392                         }
10393
10394                         // FIXME: LLVM can't handle the inconsistent bb linking
10395                         if (!mono_class_is_nullable (klass) &&
10396                                 !mini_is_gsharedvt_klass (klass) &&
10397                                 ip + 5 < end && ip_in_bb (cfg, cfg->cbb, ip + 5) &&
10398                                 (ip [5] == CEE_BRTRUE || 
10399                                  ip [5] == CEE_BRTRUE_S ||
10400                                  ip [5] == CEE_BRFALSE ||
10401                                  ip [5] == CEE_BRFALSE_S)) {
10402                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
10403                                 int dreg;
10404                                 MonoBasicBlock *true_bb, *false_bb;
10405
10406                                 ip += 5;
10407
10408                                 if (cfg->verbose_level > 3) {
10409                                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
10410                                         printf ("<box+brtrue opt>\n");
10411                                 }
10412
10413                                 switch (*ip) {
10414                                 case CEE_BRTRUE_S:
10415                                 case CEE_BRFALSE_S:
10416                                         CHECK_OPSIZE (2);
10417                                         ip++;
10418                                         target = ip + 1 + (signed char)(*ip);
10419                                         ip++;
10420                                         break;
10421                                 case CEE_BRTRUE:
10422                                 case CEE_BRFALSE:
10423                                         CHECK_OPSIZE (5);
10424                                         ip++;
10425                                         target = ip + 4 + (gint)(read32 (ip));
10426                                         ip += 4;
10427                                         break;
10428                                 default:
10429                                         g_assert_not_reached ();
10430                                 }
10431
10432                                 /* 
10433                                  * We need to link both bblocks, since it is needed for handling stack
10434                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
10435                                  * Branching to only one of them would lead to inconsistencies, so
10436                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
10437                                  */
10438                                 GET_BBLOCK (cfg, true_bb, target);
10439                                 GET_BBLOCK (cfg, false_bb, ip);
10440
10441                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
10442                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
10443
10444                                 if (sp != stack_start) {
10445                                         handle_stack_args (cfg, stack_start, sp - stack_start);
10446                                         sp = stack_start;
10447                                         CHECK_UNVERIFIABLE (cfg);
10448                                 }
10449
10450                                 if (COMPILE_LLVM (cfg)) {
10451                                         dreg = alloc_ireg (cfg);
10452                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
10453                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
10454
10455                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
10456                                 } else {
10457                                         /* The JIT can't eliminate the iconst+compare */
10458                                         MONO_INST_NEW (cfg, ins, OP_BR);
10459                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
10460                                         MONO_ADD_INS (cfg->cbb, ins);
10461                                 }
10462
10463                                 start_new_bblock = 1;
10464                                 break;
10465                         }
10466
10467                         *sp++ = handle_box (cfg, val, klass, context_used);
10468
10469                         CHECK_CFG_EXCEPTION;
10470                         ip += 5;
10471                         inline_costs += 1;
10472                         break;
10473                 }
10474                 case CEE_UNBOX: {
10475                         CHECK_STACK (1);
10476                         --sp;
10477                         CHECK_OPSIZE (5);
10478                         token = read32 (ip + 1);
10479                         klass = mini_get_class (method, token, generic_context);
10480                         CHECK_TYPELOAD (klass);
10481
10482                         mono_save_token_info (cfg, image, token, klass);
10483
10484                         context_used = mini_class_check_context_used (cfg, klass);
10485
10486                         if (mono_class_is_nullable (klass)) {
10487                                 MonoInst *val;
10488
10489                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
10490                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
10491
10492                                 *sp++= ins;
10493                         } else {
10494                                 ins = handle_unbox (cfg, klass, sp, context_used);
10495                                 *sp++ = ins;
10496                         }
10497                         ip += 5;
10498                         inline_costs += 2;
10499                         break;
10500                 }
10501                 case CEE_LDFLD:
10502                 case CEE_LDFLDA:
10503                 case CEE_STFLD:
10504                 case CEE_LDSFLD:
10505                 case CEE_LDSFLDA:
10506                 case CEE_STSFLD: {
10507                         MonoClassField *field;
10508 #ifndef DISABLE_REMOTING
10509                         int costs;
10510 #endif
10511                         guint foffset;
10512                         gboolean is_instance;
10513                         int op;
10514                         gpointer addr = NULL;
10515                         gboolean is_special_static;
10516                         MonoType *ftype;
10517                         MonoInst *store_val = NULL;
10518                         MonoInst *thread_ins;
10519
10520                         op = *ip;
10521                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
10522                         if (is_instance) {
10523                                 if (op == CEE_STFLD) {
10524                                         CHECK_STACK (2);
10525                                         sp -= 2;
10526                                         store_val = sp [1];
10527                                 } else {
10528                                         CHECK_STACK (1);
10529                                         --sp;
10530                                 }
10531                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
10532                                         UNVERIFIED;
10533                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
10534                                         UNVERIFIED;
10535                         } else {
10536                                 if (op == CEE_STSFLD) {
10537                                         CHECK_STACK (1);
10538                                         sp--;
10539                                         store_val = sp [0];
10540                                 }
10541                         }
10542
10543                         CHECK_OPSIZE (5);
10544                         token = read32 (ip + 1);
10545                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
10546                                 field = (MonoClassField *)mono_method_get_wrapper_data (method, token);
10547                                 klass = field->parent;
10548                         }
10549                         else {
10550                                 field = mono_field_from_token_checked (image, token, &klass, generic_context, &cfg->error);
10551                                 CHECK_CFG_ERROR;
10552                         }
10553                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
10554                                 FIELD_ACCESS_FAILURE (method, field);
10555                         mono_class_init (klass);
10556
10557                         /* if the class is Critical then transparent code cannot access it's fields */
10558                         if (!is_instance && mono_security_core_clr_enabled ())
10559                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
10560
10561                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
10562                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
10563                         if (mono_security_core_clr_enabled ())
10564                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
10565                         */
10566
10567                         ftype = mono_field_get_type (field);
10568
10569                         /*
10570                          * LDFLD etc. is usable on static fields as well, so convert those cases to
10571                          * the static case.
10572                          */
10573                         if (is_instance && ftype->attrs & FIELD_ATTRIBUTE_STATIC) {
10574                                 switch (op) {
10575                                 case CEE_LDFLD:
10576                                         op = CEE_LDSFLD;
10577                                         break;
10578                                 case CEE_STFLD:
10579                                         op = CEE_STSFLD;
10580                                         break;
10581                                 case CEE_LDFLDA:
10582                                         op = CEE_LDSFLDA;
10583                                         break;
10584                                 default:
10585                                         g_assert_not_reached ();
10586                                 }
10587                                 is_instance = FALSE;
10588                         }
10589
10590                         context_used = mini_class_check_context_used (cfg, klass);
10591
10592                         /* INSTANCE CASE */
10593
10594                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
10595                         if (op == CEE_STFLD) {
10596                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
10597                                         UNVERIFIED;
10598 #ifndef DISABLE_REMOTING
10599                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
10600                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
10601                                         MonoInst *iargs [5];
10602
10603                                         GSHAREDVT_FAILURE (op);
10604
10605                                         iargs [0] = sp [0];
10606                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10607                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
10608                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
10609                                                     field->offset);
10610                                         iargs [4] = sp [1];
10611
10612                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
10613                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
10614                                                                                            iargs, ip, cfg->real_offset, TRUE);
10615                                                 CHECK_CFG_EXCEPTION;
10616                                                 g_assert (costs > 0);
10617                                                       
10618                                                 cfg->real_offset += 5;
10619
10620                                                 inline_costs += costs;
10621                                         } else {
10622                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
10623                                         }
10624                                 } else
10625 #endif
10626                                 {
10627                                         MonoInst *store, *wbarrier_ptr_ins = NULL;
10628
10629                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
10630
10631                                         if (ins_flag & MONO_INST_VOLATILE) {
10632                                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
10633                                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
10634                                         }
10635
10636                                         if (mini_is_gsharedvt_klass (klass)) {
10637                                                 MonoInst *offset_ins;
10638
10639                                                 context_used = mini_class_check_context_used (cfg, klass);
10640
10641                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10642                                                 /* The value is offset by 1 */
10643                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
10644                                                 dreg = alloc_ireg_mp (cfg);
10645                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10646                                                 wbarrier_ptr_ins = ins;
10647                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
10648                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
10649                                         } else {
10650                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
10651                                         }
10652                                         if (sp [0]->opcode != OP_LDADDR)
10653                                                 store->flags |= MONO_INST_FAULT;
10654
10655                                         if (cfg->gen_write_barriers && mini_type_to_stind (cfg, field->type) == CEE_STIND_REF && !MONO_INS_IS_PCONST_NULL (sp [1])) {
10656                                                 if (mini_is_gsharedvt_klass (klass)) {
10657                                                         g_assert (wbarrier_ptr_ins);
10658                                                         emit_write_barrier (cfg, wbarrier_ptr_ins, sp [1]);
10659                                                 } else {
10660                                                         /* insert call to write barrier */
10661                                                         MonoInst *ptr;
10662                                                         int dreg;
10663
10664                                                         dreg = alloc_ireg_mp (cfg);
10665                                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10666                                                         emit_write_barrier (cfg, ptr, sp [1]);
10667                                                 }
10668                                         }
10669
10670                                         store->flags |= ins_flag;
10671                                 }
10672                                 ins_flag = 0;
10673                                 ip += 5;
10674                                 break;
10675                         }
10676
10677 #ifndef DISABLE_REMOTING
10678                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
10679                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
10680                                 MonoInst *iargs [4];
10681
10682                                 GSHAREDVT_FAILURE (op);
10683
10684                                 iargs [0] = sp [0];
10685                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10686                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
10687                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
10688                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
10689                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
10690                                                                                    iargs, ip, cfg->real_offset, TRUE);
10691                                         CHECK_CFG_EXCEPTION;
10692                                         g_assert (costs > 0);
10693                                                       
10694                                         cfg->real_offset += 5;
10695
10696                                         *sp++ = iargs [0];
10697
10698                                         inline_costs += costs;
10699                                 } else {
10700                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
10701                                         *sp++ = ins;
10702                                 }
10703                         } else 
10704 #endif
10705                         if (is_instance) {
10706                                 if (sp [0]->type == STACK_VTYPE) {
10707                                         MonoInst *var;
10708
10709                                         /* Have to compute the address of the variable */
10710
10711                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
10712                                         if (!var)
10713                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
10714                                         else
10715                                                 g_assert (var->klass == klass);
10716                                         
10717                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
10718                                         sp [0] = ins;
10719                                 }
10720
10721                                 if (op == CEE_LDFLDA) {
10722                                         if (sp [0]->type == STACK_OBJ) {
10723                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
10724                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
10725                                         }
10726
10727                                         dreg = alloc_ireg_mp (cfg);
10728
10729                                         if (mini_is_gsharedvt_klass (klass)) {
10730                                                 MonoInst *offset_ins;
10731
10732                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10733                                                 /* The value is offset by 1 */
10734                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
10735                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10736                                         } else {
10737                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10738                                         }
10739                                         ins->klass = mono_class_from_mono_type (field->type);
10740                                         ins->type = STACK_MP;
10741                                         *sp++ = ins;
10742                                 } else {
10743                                         MonoInst *load;
10744
10745                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
10746
10747                                         if (sp [0]->opcode == OP_LDADDR && klass->simd_type && cfg->opt & MONO_OPT_SIMD) {
10748                                                 ins = mono_emit_simd_field_load (cfg, field, sp [0]);
10749                                                 if (ins) {
10750                                                         *sp++ = ins;
10751                                                         ins_flag = 0;
10752                                                         ip += 5;
10753                                                         break;
10754                                                 }
10755                                         }
10756
10757                                         if (mini_is_gsharedvt_klass (klass)) {
10758                                                 MonoInst *offset_ins;
10759
10760                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10761                                                 /* The value is offset by 1 */
10762                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
10763                                                 dreg = alloc_ireg_mp (cfg);
10764                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10765                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
10766                                         } else {
10767                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
10768                                         }
10769                                         load->flags |= ins_flag;
10770                                         if (sp [0]->opcode != OP_LDADDR)
10771                                                 load->flags |= MONO_INST_FAULT;
10772                                         *sp++ = load;
10773                                 }
10774                         }
10775
10776                         if (is_instance) {
10777                                 ins_flag = 0;
10778                                 ip += 5;
10779                                 break;
10780                         }
10781
10782                         /* STATIC CASE */
10783                         context_used = mini_class_check_context_used (cfg, klass);
10784
10785                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL) {
10786                                 mono_error_set_field_load (&cfg->error, field->parent, field->name, "Using static instructions with literal field");
10787                                 CHECK_CFG_ERROR;
10788                         }
10789
10790                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
10791                          * to be called here.
10792                          */
10793                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
10794                                 mono_class_vtable (cfg->domain, klass);
10795                                 CHECK_TYPELOAD (klass);
10796                         }
10797                         mono_domain_lock (cfg->domain);
10798                         if (cfg->domain->special_static_fields)
10799                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
10800                         mono_domain_unlock (cfg->domain);
10801
10802                         is_special_static = mono_class_field_is_special_static (field);
10803
10804                         if (is_special_static && ((gsize)addr & 0x80000000) == 0)
10805                                 thread_ins = mono_get_thread_intrinsic (cfg);
10806                         else
10807                                 thread_ins = NULL;
10808
10809                         /* Generate IR to compute the field address */
10810                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
10811                                 /*
10812                                  * Fast access to TLS data
10813                                  * Inline version of get_thread_static_data () in
10814                                  * threads.c.
10815                                  */
10816                                 guint32 offset;
10817                                 int idx, static_data_reg, array_reg, dreg;
10818
10819                                 GSHAREDVT_FAILURE (op);
10820
10821                                 MONO_ADD_INS (cfg->cbb, thread_ins);
10822                                 static_data_reg = alloc_ireg (cfg);
10823                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
10824
10825                                 if (cfg->compile_aot) {
10826                                         int offset_reg, offset2_reg, idx_reg;
10827
10828                                         /* For TLS variables, this will return the TLS offset */
10829                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
10830                                         offset_reg = ins->dreg;
10831                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
10832                                         idx_reg = alloc_ireg (cfg);
10833                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, idx_reg, offset_reg, 0x3f);
10834                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
10835                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
10836                                         array_reg = alloc_ireg (cfg);
10837                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
10838                                         offset2_reg = alloc_ireg (cfg);
10839                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, offset2_reg, offset_reg, 6);
10840                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset2_reg, 0x1ffffff);
10841                                         dreg = alloc_ireg (cfg);
10842                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
10843                                 } else {
10844                                         offset = (gsize)addr & 0x7fffffff;
10845                                         idx = offset & 0x3f;
10846
10847                                         array_reg = alloc_ireg (cfg);
10848                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
10849                                         dreg = alloc_ireg (cfg);
10850                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, ((offset >> 6) & 0x1ffffff));
10851                                 }
10852                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
10853                                         (cfg->compile_aot && is_special_static) ||
10854                                         (context_used && is_special_static)) {
10855                                 MonoInst *iargs [2];
10856
10857                                 g_assert (field->parent);
10858                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10859                                 if (context_used) {
10860                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
10861                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
10862                                 } else {
10863                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
10864                                 }
10865                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
10866                         } else if (context_used) {
10867                                 MonoInst *static_data;
10868
10869                                 /*
10870                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
10871                                         method->klass->name_space, method->klass->name, method->name,
10872                                         depth, field->offset);
10873                                 */
10874
10875                                 if (mono_class_needs_cctor_run (klass, method))
10876                                         emit_class_init (cfg, klass);
10877
10878                                 /*
10879                                  * The pointer we're computing here is
10880                                  *
10881                                  *   super_info.static_data + field->offset
10882                                  */
10883                                 static_data = mini_emit_get_rgctx_klass (cfg, context_used,
10884                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
10885
10886                                 if (mini_is_gsharedvt_klass (klass)) {
10887                                         MonoInst *offset_ins;
10888
10889                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10890                                         /* The value is offset by 1 */
10891                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
10892                                         dreg = alloc_ireg_mp (cfg);
10893                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
10894                                 } else if (field->offset == 0) {
10895                                         ins = static_data;
10896                                 } else {
10897                                         int addr_reg = mono_alloc_preg (cfg);
10898                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
10899                                 }
10900                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
10901                                 MonoInst *iargs [2];
10902
10903                                 g_assert (field->parent);
10904                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10905                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
10906                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
10907                         } else {
10908                                 MonoVTable *vtable = NULL;
10909
10910                                 if (!cfg->compile_aot)
10911                                         vtable = mono_class_vtable (cfg->domain, klass);
10912                                 CHECK_TYPELOAD (klass);
10913
10914                                 if (!addr) {
10915                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
10916                                                 if (!(g_slist_find (class_inits, klass))) {
10917                                                         emit_class_init (cfg, klass);
10918                                                         if (cfg->verbose_level > 2)
10919                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
10920                                                         class_inits = g_slist_prepend (class_inits, klass);
10921                                                 }
10922                                         } else {
10923                                                 if (cfg->run_cctors) {
10924                                                         /* This makes so that inline cannot trigger */
10925                                                         /* .cctors: too many apps depend on them */
10926                                                         /* running with a specific order... */
10927                                                         g_assert (vtable);
10928                                                         if (! vtable->initialized)
10929                                                                 INLINE_FAILURE ("class init");
10930                                                         if (!mono_runtime_class_init_full (vtable, &cfg->error)) {
10931                                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
10932                                                                 goto exception_exit;
10933                                                         }
10934                                                 }
10935                                         }
10936                                         if (cfg->compile_aot)
10937                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
10938                                         else {
10939                                                 g_assert (vtable);
10940                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
10941                                                 g_assert (addr);
10942                                                 EMIT_NEW_PCONST (cfg, ins, addr);
10943                                         }
10944                                 } else {
10945                                         MonoInst *iargs [1];
10946                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
10947                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
10948                                 }
10949                         }
10950
10951                         /* Generate IR to do the actual load/store operation */
10952
10953                         if ((op == CEE_STFLD || op == CEE_STSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
10954                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
10955                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
10956                         }
10957
10958                         if (op == CEE_LDSFLDA) {
10959                                 ins->klass = mono_class_from_mono_type (ftype);
10960                                 ins->type = STACK_PTR;
10961                                 *sp++ = ins;
10962                         } else if (op == CEE_STSFLD) {
10963                                 MonoInst *store;
10964
10965                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
10966                                 store->flags |= ins_flag;
10967                         } else {
10968                                 gboolean is_const = FALSE;
10969                                 MonoVTable *vtable = NULL;
10970                                 gpointer addr = NULL;
10971
10972                                 if (!context_used) {
10973                                         vtable = mono_class_vtable (cfg->domain, klass);
10974                                         CHECK_TYPELOAD (klass);
10975                                 }
10976                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
10977                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
10978                                         int ro_type = ftype->type;
10979                                         if (!addr)
10980                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
10981                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
10982                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
10983                                         }
10984
10985                                         GSHAREDVT_FAILURE (op);
10986
10987                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
10988                                         is_const = TRUE;
10989                                         switch (ro_type) {
10990                                         case MONO_TYPE_BOOLEAN:
10991                                         case MONO_TYPE_U1:
10992                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
10993                                                 sp++;
10994                                                 break;
10995                                         case MONO_TYPE_I1:
10996                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
10997                                                 sp++;
10998                                                 break;                                          
10999                                         case MONO_TYPE_CHAR:
11000                                         case MONO_TYPE_U2:
11001                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
11002                                                 sp++;
11003                                                 break;
11004                                         case MONO_TYPE_I2:
11005                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
11006                                                 sp++;
11007                                                 break;
11008                                                 break;
11009                                         case MONO_TYPE_I4:
11010                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
11011                                                 sp++;
11012                                                 break;                                          
11013                                         case MONO_TYPE_U4:
11014                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
11015                                                 sp++;
11016                                                 break;
11017                                         case MONO_TYPE_I:
11018                                         case MONO_TYPE_U:
11019                                         case MONO_TYPE_PTR:
11020                                         case MONO_TYPE_FNPTR:
11021                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11022                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
11023                                                 sp++;
11024                                                 break;
11025                                         case MONO_TYPE_STRING:
11026                                         case MONO_TYPE_OBJECT:
11027                                         case MONO_TYPE_CLASS:
11028                                         case MONO_TYPE_SZARRAY:
11029                                         case MONO_TYPE_ARRAY:
11030                                                 if (!mono_gc_is_moving ()) {
11031                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11032                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
11033                                                         sp++;
11034                                                 } else {
11035                                                         is_const = FALSE;
11036                                                 }
11037                                                 break;
11038                                         case MONO_TYPE_I8:
11039                                         case MONO_TYPE_U8:
11040                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
11041                                                 sp++;
11042                                                 break;
11043                                         case MONO_TYPE_R4:
11044                                         case MONO_TYPE_R8:
11045                                         case MONO_TYPE_VALUETYPE:
11046                                         default:
11047                                                 is_const = FALSE;
11048                                                 break;
11049                                         }
11050                                 }
11051
11052                                 if (!is_const) {
11053                                         MonoInst *load;
11054
11055                                         CHECK_STACK_OVF (1);
11056
11057                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
11058                                         load->flags |= ins_flag;
11059                                         ins_flag = 0;
11060                                         *sp++ = load;
11061                                 }
11062                         }
11063
11064                         if ((op == CEE_LDFLD || op == CEE_LDSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11065                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
11066                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
11067                         }
11068
11069                         ins_flag = 0;
11070                         ip += 5;
11071                         break;
11072                 }
11073                 case CEE_STOBJ:
11074                         CHECK_STACK (2);
11075                         sp -= 2;
11076                         CHECK_OPSIZE (5);
11077                         token = read32 (ip + 1);
11078                         klass = mini_get_class (method, token, generic_context);
11079                         CHECK_TYPELOAD (klass);
11080                         if (ins_flag & MONO_INST_VOLATILE) {
11081                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11082                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11083                         }
11084                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
11085                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
11086                         ins->flags |= ins_flag;
11087                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
11088                                 generic_class_is_reference_type (cfg, klass) && !MONO_INS_IS_PCONST_NULL (sp [1])) {
11089                                 /* insert call to write barrier */
11090                                 emit_write_barrier (cfg, sp [0], sp [1]);
11091                         }
11092                         ins_flag = 0;
11093                         ip += 5;
11094                         inline_costs += 1;
11095                         break;
11096
11097                         /*
11098                          * Array opcodes
11099                          */
11100                 case CEE_NEWARR: {
11101                         MonoInst *len_ins;
11102                         const char *data_ptr;
11103                         int data_size = 0;
11104                         guint32 field_token;
11105
11106                         CHECK_STACK (1);
11107                         --sp;
11108
11109                         CHECK_OPSIZE (5);
11110                         token = read32 (ip + 1);
11111
11112                         klass = mini_get_class (method, token, generic_context);
11113                         CHECK_TYPELOAD (klass);
11114
11115                         context_used = mini_class_check_context_used (cfg, klass);
11116
11117                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
11118                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
11119                                 ins->sreg1 = sp [0]->dreg;
11120                                 ins->type = STACK_I4;
11121                                 ins->dreg = alloc_ireg (cfg);
11122                                 MONO_ADD_INS (cfg->cbb, ins);
11123                                 *sp = mono_decompose_opcode (cfg, ins);
11124                         }
11125
11126                         if (context_used) {
11127                                 MonoInst *args [3];
11128                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11129                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
11130
11131                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
11132
11133                                 /* vtable */
11134                                 args [0] = mini_emit_get_rgctx_klass (cfg, context_used,
11135                                         array_class, MONO_RGCTX_INFO_VTABLE);
11136                                 /* array len */
11137                                 args [1] = sp [0];
11138
11139                                 if (managed_alloc)
11140                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
11141                                 else
11142                                         ins = mono_emit_jit_icall (cfg, ves_icall_array_new_specific, args);
11143                         } else {
11144                                 if (cfg->opt & MONO_OPT_SHARED) {
11145                                         /* Decompose now to avoid problems with references to the domainvar */
11146                                         MonoInst *iargs [3];
11147
11148                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11149                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11150                                         iargs [2] = sp [0];
11151
11152                                         ins = mono_emit_jit_icall (cfg, ves_icall_array_new, iargs);
11153                                 } else {
11154                                         /* Decompose later since it is needed by abcrem */
11155                                         MonoClass *array_type = mono_array_class_get (klass, 1);
11156                                         mono_class_vtable (cfg->domain, array_type);
11157                                         CHECK_TYPELOAD (array_type);
11158
11159                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
11160                                         ins->dreg = alloc_ireg_ref (cfg);
11161                                         ins->sreg1 = sp [0]->dreg;
11162                                         ins->inst_newa_class = klass;
11163                                         ins->type = STACK_OBJ;
11164                                         ins->klass = array_type;
11165                                         MONO_ADD_INS (cfg->cbb, ins);
11166                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11167                                         cfg->cbb->has_array_access = TRUE;
11168
11169                                         /* Needed so mono_emit_load_get_addr () gets called */
11170                                         mono_get_got_var (cfg);
11171                                 }
11172                         }
11173
11174                         len_ins = sp [0];
11175                         ip += 5;
11176                         *sp++ = ins;
11177                         inline_costs += 1;
11178
11179                         /* 
11180                          * we inline/optimize the initialization sequence if possible.
11181                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
11182                          * for small sizes open code the memcpy
11183                          * ensure the rva field is big enough
11184                          */
11185                         if ((cfg->opt & MONO_OPT_INTRINS) && ip + 6 < end && ip_in_bb (cfg, cfg->cbb, ip + 6) && (len_ins->opcode == OP_ICONST) && (data_ptr = initialize_array_data (method, cfg->compile_aot, ip, klass, len_ins->inst_c0, &data_size, &field_token))) {
11186                                 MonoMethod *memcpy_method = get_memcpy_method ();
11187                                 MonoInst *iargs [3];
11188                                 int add_reg = alloc_ireg_mp (cfg);
11189
11190                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, MONO_STRUCT_OFFSET (MonoArray, vector));
11191                                 if (cfg->compile_aot) {
11192                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
11193                                 } else {
11194                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
11195                                 }
11196                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
11197                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
11198                                 ip += 11;
11199                         }
11200
11201                         break;
11202                 }
11203                 case CEE_LDLEN:
11204                         CHECK_STACK (1);
11205                         --sp;
11206                         if (sp [0]->type != STACK_OBJ)
11207                                 UNVERIFIED;
11208
11209                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
11210                         ins->dreg = alloc_preg (cfg);
11211                         ins->sreg1 = sp [0]->dreg;
11212                         ins->type = STACK_I4;
11213                         /* This flag will be inherited by the decomposition */
11214                         ins->flags |= MONO_INST_FAULT;
11215                         MONO_ADD_INS (cfg->cbb, ins);
11216                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11217                         cfg->cbb->has_array_access = TRUE;
11218                         ip ++;
11219                         *sp++ = ins;
11220                         break;
11221                 case CEE_LDELEMA:
11222                         CHECK_STACK (2);
11223                         sp -= 2;
11224                         CHECK_OPSIZE (5);
11225                         if (sp [0]->type != STACK_OBJ)
11226                                 UNVERIFIED;
11227
11228                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11229
11230                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11231                         CHECK_TYPELOAD (klass);
11232                         /* we need to make sure that this array is exactly the type it needs
11233                          * to be for correctness. the wrappers are lax with their usage
11234                          * so we need to ignore them here
11235                          */
11236                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
11237                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11238                                 mini_emit_check_array_type (cfg, sp [0], array_class);
11239                                 CHECK_TYPELOAD (array_class);
11240                         }
11241
11242                         readonly = FALSE;
11243                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11244                         *sp++ = ins;
11245                         ip += 5;
11246                         break;
11247                 case CEE_LDELEM:
11248                 case CEE_LDELEM_I1:
11249                 case CEE_LDELEM_U1:
11250                 case CEE_LDELEM_I2:
11251                 case CEE_LDELEM_U2:
11252                 case CEE_LDELEM_I4:
11253                 case CEE_LDELEM_U4:
11254                 case CEE_LDELEM_I8:
11255                 case CEE_LDELEM_I:
11256                 case CEE_LDELEM_R4:
11257                 case CEE_LDELEM_R8:
11258                 case CEE_LDELEM_REF: {
11259                         MonoInst *addr;
11260
11261                         CHECK_STACK (2);
11262                         sp -= 2;
11263
11264                         if (*ip == CEE_LDELEM) {
11265                                 CHECK_OPSIZE (5);
11266                                 token = read32 (ip + 1);
11267                                 klass = mini_get_class (method, token, generic_context);
11268                                 CHECK_TYPELOAD (klass);
11269                                 mono_class_init (klass);
11270                         }
11271                         else
11272                                 klass = array_access_to_klass (*ip);
11273
11274                         if (sp [0]->type != STACK_OBJ)
11275                                 UNVERIFIED;
11276
11277                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11278
11279                         if (mini_is_gsharedvt_variable_klass (klass)) {
11280                                 // FIXME-VT: OP_ICONST optimization
11281                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11282                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11283                                 ins->opcode = OP_LOADV_MEMBASE;
11284                         } else if (sp [1]->opcode == OP_ICONST) {
11285                                 int array_reg = sp [0]->dreg;
11286                                 int index_reg = sp [1]->dreg;
11287                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
11288
11289                                 if (SIZEOF_REGISTER == 8 && COMPILE_LLVM (cfg))
11290                                         MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, index_reg);
11291
11292                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
11293                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
11294                         } else {
11295                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11296                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11297                         }
11298                         *sp++ = ins;
11299                         if (*ip == CEE_LDELEM)
11300                                 ip += 5;
11301                         else
11302                                 ++ip;
11303                         break;
11304                 }
11305                 case CEE_STELEM_I:
11306                 case CEE_STELEM_I1:
11307                 case CEE_STELEM_I2:
11308                 case CEE_STELEM_I4:
11309                 case CEE_STELEM_I8:
11310                 case CEE_STELEM_R4:
11311                 case CEE_STELEM_R8:
11312                 case CEE_STELEM_REF:
11313                 case CEE_STELEM: {
11314                         CHECK_STACK (3);
11315                         sp -= 3;
11316
11317                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11318
11319                         if (*ip == CEE_STELEM) {
11320                                 CHECK_OPSIZE (5);
11321                                 token = read32 (ip + 1);
11322                                 klass = mini_get_class (method, token, generic_context);
11323                                 CHECK_TYPELOAD (klass);
11324                                 mono_class_init (klass);
11325                         }
11326                         else
11327                                 klass = array_access_to_klass (*ip);
11328
11329                         if (sp [0]->type != STACK_OBJ)
11330                                 UNVERIFIED;
11331
11332                         emit_array_store (cfg, klass, sp, TRUE);
11333
11334                         if (*ip == CEE_STELEM)
11335                                 ip += 5;
11336                         else
11337                                 ++ip;
11338                         inline_costs += 1;
11339                         break;
11340                 }
11341                 case CEE_CKFINITE: {
11342                         CHECK_STACK (1);
11343                         --sp;
11344
11345                         if (cfg->llvm_only) {
11346                                 MonoInst *iargs [1];
11347
11348                                 iargs [0] = sp [0];
11349                                 *sp++ = mono_emit_jit_icall (cfg, mono_ckfinite, iargs);
11350                         } else  {
11351                                 MONO_INST_NEW (cfg, ins, OP_CKFINITE);
11352                                 ins->sreg1 = sp [0]->dreg;
11353                                 ins->dreg = alloc_freg (cfg);
11354                                 ins->type = STACK_R8;
11355                                 MONO_ADD_INS (cfg->cbb, ins);
11356
11357                                 *sp++ = mono_decompose_opcode (cfg, ins);
11358                         }
11359
11360                         ++ip;
11361                         break;
11362                 }
11363                 case CEE_REFANYVAL: {
11364                         MonoInst *src_var, *src;
11365
11366                         int klass_reg = alloc_preg (cfg);
11367                         int dreg = alloc_preg (cfg);
11368
11369                         GSHAREDVT_FAILURE (*ip);
11370
11371                         CHECK_STACK (1);
11372                         MONO_INST_NEW (cfg, ins, *ip);
11373                         --sp;
11374                         CHECK_OPSIZE (5);
11375                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11376                         CHECK_TYPELOAD (klass);
11377
11378                         context_used = mini_class_check_context_used (cfg, klass);
11379
11380                         // FIXME:
11381                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11382                         if (!src_var)
11383                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
11384                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
11385                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass));
11386
11387                         if (context_used) {
11388                                 MonoInst *klass_ins;
11389
11390                                 klass_ins = mini_emit_get_rgctx_klass (cfg, context_used,
11391                                                 klass, MONO_RGCTX_INFO_KLASS);
11392
11393                                 // FIXME:
11394                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
11395                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
11396                         } else {
11397                                 mini_emit_class_check (cfg, klass_reg, klass);
11398                         }
11399                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value));
11400                         ins->type = STACK_MP;
11401                         ins->klass = klass;
11402                         *sp++ = ins;
11403                         ip += 5;
11404                         break;
11405                 }
11406                 case CEE_MKREFANY: {
11407                         MonoInst *loc, *addr;
11408
11409                         GSHAREDVT_FAILURE (*ip);
11410
11411                         CHECK_STACK (1);
11412                         MONO_INST_NEW (cfg, ins, *ip);
11413                         --sp;
11414                         CHECK_OPSIZE (5);
11415                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11416                         CHECK_TYPELOAD (klass);
11417
11418                         context_used = mini_class_check_context_used (cfg, klass);
11419
11420                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
11421                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
11422
11423                         if (context_used) {
11424                                 MonoInst *const_ins;
11425                                 int type_reg = alloc_preg (cfg);
11426
11427                                 const_ins = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
11428                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
11429                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11430                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11431                         } else {
11432                                 int const_reg = alloc_preg (cfg);
11433                                 int type_reg = alloc_preg (cfg);
11434
11435                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
11436                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
11437                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11438                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11439                         }
11440                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
11441
11442                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
11443                         ins->type = STACK_VTYPE;
11444                         ins->klass = mono_defaults.typed_reference_class;
11445                         *sp++ = ins;
11446                         ip += 5;
11447                         break;
11448                 }
11449                 case CEE_LDTOKEN: {
11450                         gpointer handle;
11451                         MonoClass *handle_class;
11452
11453                         CHECK_STACK_OVF (1);
11454
11455                         CHECK_OPSIZE (5);
11456                         n = read32 (ip + 1);
11457
11458                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
11459                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
11460                                 handle = mono_method_get_wrapper_data (method, n);
11461                                 handle_class = (MonoClass *)mono_method_get_wrapper_data (method, n + 1);
11462                                 if (handle_class == mono_defaults.typehandle_class)
11463                                         handle = &((MonoClass*)handle)->byval_arg;
11464                         }
11465                         else {
11466                                 handle = mono_ldtoken_checked (image, n, &handle_class, generic_context, &cfg->error);
11467                                 CHECK_CFG_ERROR;
11468                         }
11469                         if (!handle)
11470                                 LOAD_ERROR;
11471                         mono_class_init (handle_class);
11472                         if (cfg->gshared) {
11473                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
11474                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
11475                                         /* This case handles ldtoken
11476                                            of an open type, like for
11477                                            typeof(Gen<>). */
11478                                         context_used = 0;
11479                                 } else if (handle_class == mono_defaults.typehandle_class) {
11480                                         context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type ((MonoType *)handle));
11481                                 } else if (handle_class == mono_defaults.fieldhandle_class)
11482                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
11483                                 else if (handle_class == mono_defaults.methodhandle_class)
11484                                         context_used = mini_method_check_context_used (cfg, (MonoMethod *)handle);
11485                                 else
11486                                         g_assert_not_reached ();
11487                         }
11488
11489                         if ((cfg->opt & MONO_OPT_SHARED) &&
11490                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
11491                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
11492                                 MonoInst *addr, *vtvar, *iargs [3];
11493                                 int method_context_used;
11494
11495                                 method_context_used = mini_method_check_context_used (cfg, method);
11496
11497                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
11498
11499                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
11500                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
11501                                 if (method_context_used) {
11502                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
11503                                                 method, MONO_RGCTX_INFO_METHOD);
11504                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
11505                                 } else {
11506                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
11507                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
11508                                 }
11509                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11510
11511                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11512
11513                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11514                         } else {
11515                                 if ((ip + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 5) && 
11516                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
11517                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
11518                                         (cmethod->klass == mono_defaults.systemtype_class) &&
11519                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
11520                                         MonoClass *tclass = mono_class_from_mono_type ((MonoType *)handle);
11521
11522                                         mono_class_init (tclass);
11523                                         if (context_used) {
11524                                                 ins = mini_emit_get_rgctx_klass (cfg, context_used,
11525                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
11526                                         } else if (cfg->compile_aot) {
11527                                                 if (method->wrapper_type) {
11528                                                         mono_error_init (&error); //got to do it since there are multiple conditionals below
11529                                                         if (mono_class_get_checked (tclass->image, tclass->type_token, &error) == tclass && !generic_context) {
11530                                                                 /* Special case for static synchronized wrappers */
11531                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
11532                                                         } else {
11533                                                                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
11534                                                                 /* FIXME: n is not a normal token */
11535                                                                 DISABLE_AOT (cfg);
11536                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11537                                                         }
11538                                                 } else {
11539                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
11540                                                 }
11541                                         } else {
11542                                                 MonoReflectionType *rt = mono_type_get_object_checked (cfg->domain, (MonoType *)handle, &cfg->error);
11543                                                 CHECK_CFG_ERROR;
11544                                                 EMIT_NEW_PCONST (cfg, ins, rt);
11545                                         }
11546                                         ins->type = STACK_OBJ;
11547                                         ins->klass = cmethod->klass;
11548                                         ip += 5;
11549                                 } else {
11550                                         MonoInst *addr, *vtvar;
11551
11552                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
11553
11554                                         if (context_used) {
11555                                                 if (handle_class == mono_defaults.typehandle_class) {
11556                                                         ins = mini_emit_get_rgctx_klass (cfg, context_used,
11557                                                                         mono_class_from_mono_type ((MonoType *)handle),
11558                                                                         MONO_RGCTX_INFO_TYPE);
11559                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
11560                                                         ins = emit_get_rgctx_method (cfg, context_used,
11561                                                                         (MonoMethod *)handle, MONO_RGCTX_INFO_METHOD);
11562                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
11563                                                         ins = emit_get_rgctx_field (cfg, context_used,
11564                                                                         (MonoClassField *)handle, MONO_RGCTX_INFO_CLASS_FIELD);
11565                                                 } else {
11566                                                         g_assert_not_reached ();
11567                                                 }
11568                                         } else if (cfg->compile_aot) {
11569                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
11570                                         } else {
11571                                                 EMIT_NEW_PCONST (cfg, ins, handle);
11572                                         }
11573                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11574                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11575                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11576                                 }
11577                         }
11578
11579                         *sp++ = ins;
11580                         ip += 5;
11581                         break;
11582                 }
11583                 case CEE_THROW:
11584                         CHECK_STACK (1);
11585                         if (sp [-1]->type != STACK_OBJ)
11586                                 UNVERIFIED;
11587
11588                         MONO_INST_NEW (cfg, ins, OP_THROW);
11589                         --sp;
11590                         ins->sreg1 = sp [0]->dreg;
11591                         ip++;
11592                         cfg->cbb->out_of_line = TRUE;
11593                         MONO_ADD_INS (cfg->cbb, ins);
11594                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
11595                         MONO_ADD_INS (cfg->cbb, ins);
11596                         sp = stack_start;
11597                         
11598                         link_bblock (cfg, cfg->cbb, end_bblock);
11599                         start_new_bblock = 1;
11600                         /* This can complicate code generation for llvm since the return value might not be defined */
11601                         if (COMPILE_LLVM (cfg))
11602                                 INLINE_FAILURE ("throw");
11603                         break;
11604                 case CEE_ENDFINALLY:
11605                         if (!ip_in_finally_clause (cfg, ip - header->code))
11606                                 UNVERIFIED;
11607                         /* mono_save_seq_point_info () depends on this */
11608                         if (sp != stack_start)
11609                                 emit_seq_point (cfg, method, ip, FALSE, FALSE);
11610                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
11611                         MONO_ADD_INS (cfg->cbb, ins);
11612                         ip++;
11613                         start_new_bblock = 1;
11614
11615                         /*
11616                          * Control will leave the method so empty the stack, otherwise
11617                          * the next basic block will start with a nonempty stack.
11618                          */
11619                         while (sp != stack_start) {
11620                                 sp--;
11621                         }
11622                         break;
11623                 case CEE_LEAVE:
11624                 case CEE_LEAVE_S: {
11625                         GList *handlers;
11626
11627                         if (*ip == CEE_LEAVE) {
11628                                 CHECK_OPSIZE (5);
11629                                 target = ip + 5 + (gint32)read32(ip + 1);
11630                         } else {
11631                                 CHECK_OPSIZE (2);
11632                                 target = ip + 2 + (signed char)(ip [1]);
11633                         }
11634
11635                         /* empty the stack */
11636                         while (sp != stack_start) {
11637                                 sp--;
11638                         }
11639
11640                         /* 
11641                          * If this leave statement is in a catch block, check for a
11642                          * pending exception, and rethrow it if necessary.
11643                          * We avoid doing this in runtime invoke wrappers, since those are called
11644                          * by native code which excepts the wrapper to catch all exceptions.
11645                          */
11646                         for (i = 0; i < header->num_clauses; ++i) {
11647                                 MonoExceptionClause *clause = &header->clauses [i];
11648
11649                                 /* 
11650                                  * Use <= in the final comparison to handle clauses with multiple
11651                                  * leave statements, like in bug #78024.
11652                                  * The ordering of the exception clauses guarantees that we find the
11653                                  * innermost clause.
11654                                  */
11655                                 if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && (clause->flags == MONO_EXCEPTION_CLAUSE_NONE) && (ip - header->code + ((*ip == CEE_LEAVE) ? 5 : 2)) <= (clause->handler_offset + clause->handler_len) && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE) {
11656                                         MonoInst *exc_ins;
11657                                         MonoBasicBlock *dont_throw;
11658
11659                                         /*
11660                                           MonoInst *load;
11661
11662                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
11663                                         */
11664
11665                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
11666
11667                                         NEW_BBLOCK (cfg, dont_throw);
11668
11669                                         /*
11670                                          * Currently, we always rethrow the abort exception, despite the 
11671                                          * fact that this is not correct. See thread6.cs for an example. 
11672                                          * But propagating the abort exception is more important than 
11673                                          * getting the sematics right.
11674                                          */
11675                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
11676                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
11677                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
11678
11679                                         MONO_START_BB (cfg, dont_throw);
11680                                 }
11681                         }
11682
11683 #ifdef ENABLE_LLVM
11684                         cfg->cbb->try_end = (intptr_t)(ip - header->code);
11685 #endif
11686
11687                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
11688                                 GList *tmp;
11689                                 MonoExceptionClause *clause;
11690
11691                                 for (tmp = handlers; tmp; tmp = tmp->next) {
11692                                         clause = (MonoExceptionClause *)tmp->data;
11693                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
11694                                         g_assert (tblock);
11695                                         link_bblock (cfg, cfg->cbb, tblock);
11696                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
11697                                         ins->inst_target_bb = tblock;
11698                                         ins->inst_eh_block = clause;
11699                                         MONO_ADD_INS (cfg->cbb, ins);
11700                                         cfg->cbb->has_call_handler = 1;
11701                                         if (COMPILE_LLVM (cfg)) {
11702                                                 MonoBasicBlock *target_bb;
11703
11704                                                 /* 
11705                                                  * Link the finally bblock with the target, since it will
11706                                                  * conceptually branch there.
11707                                                  */
11708                                                 GET_BBLOCK (cfg, tblock, cfg->cil_start + clause->handler_offset + clause->handler_len - 1);
11709                                                 GET_BBLOCK (cfg, target_bb, target);
11710                                                 link_bblock (cfg, tblock, target_bb);
11711                                         }
11712                                 }
11713                                 g_list_free (handlers);
11714                         } 
11715
11716                         MONO_INST_NEW (cfg, ins, OP_BR);
11717                         MONO_ADD_INS (cfg->cbb, ins);
11718                         GET_BBLOCK (cfg, tblock, target);
11719                         link_bblock (cfg, cfg->cbb, tblock);
11720                         ins->inst_target_bb = tblock;
11721
11722                         start_new_bblock = 1;
11723
11724                         if (*ip == CEE_LEAVE)
11725                                 ip += 5;
11726                         else
11727                                 ip += 2;
11728
11729                         break;
11730                 }
11731
11732                         /*
11733                          * Mono specific opcodes
11734                          */
11735                 case MONO_CUSTOM_PREFIX: {
11736
11737                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
11738
11739                         CHECK_OPSIZE (2);
11740                         switch (ip [1]) {
11741                         case CEE_MONO_ICALL: {
11742                                 gpointer func;
11743                                 MonoJitICallInfo *info;
11744
11745                                 token = read32 (ip + 2);
11746                                 func = mono_method_get_wrapper_data (method, token);
11747                                 info = mono_find_jit_icall_by_addr (func);
11748                                 if (!info)
11749                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
11750                                 g_assert (info);
11751
11752                                 CHECK_STACK (info->sig->param_count);
11753                                 sp -= info->sig->param_count;
11754
11755                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
11756                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
11757                                         *sp++ = ins;
11758
11759                                 ip += 6;
11760                                 inline_costs += 10 * num_calls++;
11761
11762                                 break;
11763                         }
11764                         case CEE_MONO_LDPTR_CARD_TABLE:
11765                         case CEE_MONO_LDPTR_NURSERY_START:
11766                         case CEE_MONO_LDPTR_NURSERY_BITS:
11767                         case CEE_MONO_LDPTR_INT_REQ_FLAG: {
11768                                 CHECK_STACK_OVF (1);
11769
11770                                 switch (ip [1]) {
11771                                         case CEE_MONO_LDPTR_CARD_TABLE:
11772                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
11773                                                 break;
11774                                         case CEE_MONO_LDPTR_NURSERY_START:
11775                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_START, NULL);
11776                                                 break;
11777                                         case CEE_MONO_LDPTR_NURSERY_BITS:
11778                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_BITS, NULL);
11779                                                 break;
11780                                         case CEE_MONO_LDPTR_INT_REQ_FLAG:
11781                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
11782                                                 break;
11783                                 }
11784
11785                                 *sp++ = ins;
11786                                 ip += 2;
11787                                 inline_costs += 10 * num_calls++;
11788                                 break;
11789                         }
11790                         case CEE_MONO_LDPTR: {
11791                                 gpointer ptr;
11792
11793                                 CHECK_STACK_OVF (1);
11794                                 CHECK_OPSIZE (6);
11795                                 token = read32 (ip + 2);
11796
11797                                 ptr = mono_method_get_wrapper_data (method, token);
11798                                 EMIT_NEW_PCONST (cfg, ins, ptr);
11799                                 *sp++ = ins;
11800                                 ip += 6;
11801                                 inline_costs += 10 * num_calls++;
11802                                 /* Can't embed random pointers into AOT code */
11803                                 DISABLE_AOT (cfg);
11804                                 break;
11805                         }
11806                         case CEE_MONO_JIT_ICALL_ADDR: {
11807                                 MonoJitICallInfo *callinfo;
11808                                 gpointer ptr;
11809
11810                                 CHECK_STACK_OVF (1);
11811                                 CHECK_OPSIZE (6);
11812                                 token = read32 (ip + 2);
11813
11814                                 ptr = mono_method_get_wrapper_data (method, token);
11815                                 callinfo = mono_find_jit_icall_by_addr (ptr);
11816                                 g_assert (callinfo);
11817                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
11818                                 *sp++ = ins;
11819                                 ip += 6;
11820                                 inline_costs += 10 * num_calls++;
11821                                 break;
11822                         }
11823                         case CEE_MONO_ICALL_ADDR: {
11824                                 MonoMethod *cmethod;
11825                                 gpointer ptr;
11826
11827                                 CHECK_STACK_OVF (1);
11828                                 CHECK_OPSIZE (6);
11829                                 token = read32 (ip + 2);
11830
11831                                 cmethod = (MonoMethod *)mono_method_get_wrapper_data (method, token);
11832
11833                                 if (cfg->compile_aot) {
11834                                         if (cfg->direct_pinvoke && ip + 6 < end && (ip [6] == CEE_POP)) {
11835                                                 /*
11836                                                  * This is generated by emit_native_wrapper () to resolve the pinvoke address
11837                                                  * before the call, its not needed when using direct pinvoke.
11838                                                  * This is not an optimization, but its used to avoid looking up pinvokes
11839                                                  * on platforms which don't support dlopen ().
11840                                                  */
11841                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11842                                         } else {
11843                                                 EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
11844                                         }
11845                                 } else {
11846                                         ptr = mono_lookup_internal_call (cmethod);
11847                                         g_assert (ptr);
11848                                         EMIT_NEW_PCONST (cfg, ins, ptr);
11849                                 }
11850                                 *sp++ = ins;
11851                                 ip += 6;
11852                                 break;
11853                         }
11854                         case CEE_MONO_VTADDR: {
11855                                 MonoInst *src_var, *src;
11856
11857                                 CHECK_STACK (1);
11858                                 --sp;
11859
11860                                 // FIXME:
11861                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11862                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
11863                                 *sp++ = src;
11864                                 ip += 2;
11865                                 break;
11866                         }
11867                         case CEE_MONO_NEWOBJ: {
11868                                 MonoInst *iargs [2];
11869
11870                                 CHECK_STACK_OVF (1);
11871                                 CHECK_OPSIZE (6);
11872                                 token = read32 (ip + 2);
11873                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11874                                 mono_class_init (klass);
11875                                 NEW_DOMAINCONST (cfg, iargs [0]);
11876                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
11877                                 NEW_CLASSCONST (cfg, iargs [1], klass);
11878                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
11879                                 *sp++ = mono_emit_jit_icall (cfg, ves_icall_object_new, iargs);
11880                                 ip += 6;
11881                                 inline_costs += 10 * num_calls++;
11882                                 break;
11883                         }
11884                         case CEE_MONO_OBJADDR:
11885                                 CHECK_STACK (1);
11886                                 --sp;
11887                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
11888                                 ins->dreg = alloc_ireg_mp (cfg);
11889                                 ins->sreg1 = sp [0]->dreg;
11890                                 ins->type = STACK_MP;
11891                                 MONO_ADD_INS (cfg->cbb, ins);
11892                                 *sp++ = ins;
11893                                 ip += 2;
11894                                 break;
11895                         case CEE_MONO_LDNATIVEOBJ:
11896                                 /*
11897                                  * Similar to LDOBJ, but instead load the unmanaged 
11898                                  * representation of the vtype to the stack.
11899                                  */
11900                                 CHECK_STACK (1);
11901                                 CHECK_OPSIZE (6);
11902                                 --sp;
11903                                 token = read32 (ip + 2);
11904                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11905                                 g_assert (klass->valuetype);
11906                                 mono_class_init (klass);
11907
11908                                 {
11909                                         MonoInst *src, *dest, *temp;
11910
11911                                         src = sp [0];
11912                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
11913                                         temp->backend.is_pinvoke = 1;
11914                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
11915                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
11916
11917                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
11918                                         dest->type = STACK_VTYPE;
11919                                         dest->klass = klass;
11920
11921                                         *sp ++ = dest;
11922                                         ip += 6;
11923                                 }
11924                                 break;
11925                         case CEE_MONO_RETOBJ: {
11926                                 /*
11927                                  * Same as RET, but return the native representation of a vtype
11928                                  * to the caller.
11929                                  */
11930                                 g_assert (cfg->ret);
11931                                 g_assert (mono_method_signature (method)->pinvoke); 
11932                                 CHECK_STACK (1);
11933                                 --sp;
11934                                 
11935                                 CHECK_OPSIZE (6);
11936                                 token = read32 (ip + 2);    
11937                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11938
11939                                 if (!cfg->vret_addr) {
11940                                         g_assert (cfg->ret_var_is_local);
11941
11942                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
11943                                 } else {
11944                                         EMIT_NEW_RETLOADA (cfg, ins);
11945                                 }
11946                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
11947                                 
11948                                 if (sp != stack_start)
11949                                         UNVERIFIED;
11950                                 
11951                                 MONO_INST_NEW (cfg, ins, OP_BR);
11952                                 ins->inst_target_bb = end_bblock;
11953                                 MONO_ADD_INS (cfg->cbb, ins);
11954                                 link_bblock (cfg, cfg->cbb, end_bblock);
11955                                 start_new_bblock = 1;
11956                                 ip += 6;
11957                                 break;
11958                         }
11959                         case CEE_MONO_SAVE_LMF:
11960                         case CEE_MONO_RESTORE_LMF:
11961                                 ip += 2;
11962                                 break;
11963                         case CEE_MONO_CLASSCONST:
11964                                 CHECK_STACK_OVF (1);
11965                                 CHECK_OPSIZE (6);
11966                                 token = read32 (ip + 2);
11967                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
11968                                 *sp++ = ins;
11969                                 ip += 6;
11970                                 inline_costs += 10 * num_calls++;
11971                                 break;
11972                         case CEE_MONO_NOT_TAKEN:
11973                                 cfg->cbb->out_of_line = TRUE;
11974                                 ip += 2;
11975                                 break;
11976                         case CEE_MONO_TLS: {
11977                                 MonoTlsKey key;
11978
11979                                 CHECK_STACK_OVF (1);
11980                                 CHECK_OPSIZE (6);
11981                                 key = (MonoTlsKey)read32 (ip + 2);
11982                                 g_assert (key < TLS_KEY_NUM);
11983
11984                                 ins = mono_create_tls_get (cfg, key);
11985                                 if (!ins) {
11986                                         if (cfg->compile_aot) {
11987                                                 DISABLE_AOT (cfg);
11988                                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
11989                                                 ins->dreg = alloc_preg (cfg);
11990                                                 ins->type = STACK_PTR;
11991                                         } else {
11992                                                 g_assert_not_reached ();
11993                                         }
11994                                 }
11995                                 ins->type = STACK_PTR;
11996                                 MONO_ADD_INS (cfg->cbb, ins);
11997                                 *sp++ = ins;
11998                                 ip += 6;
11999                                 break;
12000                         }
12001                         case CEE_MONO_DYN_CALL: {
12002                                 MonoCallInst *call;
12003
12004                                 /* It would be easier to call a trampoline, but that would put an
12005                                  * extra frame on the stack, confusing exception handling. So
12006                                  * implement it inline using an opcode for now.
12007                                  */
12008
12009                                 if (!cfg->dyn_call_var) {
12010                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12011                                         /* prevent it from being register allocated */
12012                                         cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
12013                                 }
12014
12015                                 /* Has to use a call inst since it local regalloc expects it */
12016                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
12017                                 ins = (MonoInst*)call;
12018                                 sp -= 2;
12019                                 ins->sreg1 = sp [0]->dreg;
12020                                 ins->sreg2 = sp [1]->dreg;
12021                                 MONO_ADD_INS (cfg->cbb, ins);
12022
12023                                 cfg->param_area = MAX (cfg->param_area, cfg->backend->dyn_call_param_area);
12024
12025                                 ip += 2;
12026                                 inline_costs += 10 * num_calls++;
12027
12028                                 break;
12029                         }
12030                         case CEE_MONO_MEMORY_BARRIER: {
12031                                 CHECK_OPSIZE (6);
12032                                 emit_memory_barrier (cfg, (int)read32 (ip + 2));
12033                                 ip += 6;
12034                                 break;
12035                         }
12036                         case CEE_MONO_ATOMIC_STORE_I4: {
12037                                 g_assert (mono_arch_opcode_supported (OP_ATOMIC_STORE_I4));
12038
12039                                 CHECK_OPSIZE (6);
12040                                 CHECK_STACK (2);
12041                                 sp -= 2;
12042
12043                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_STORE_I4);
12044                                 ins->dreg = sp [0]->dreg;
12045                                 ins->sreg1 = sp [1]->dreg;
12046                                 ins->backend.memory_barrier_kind = (int) read32 (ip + 2);
12047                                 MONO_ADD_INS (cfg->cbb, ins);
12048
12049                                 ip += 6;
12050                                 break;
12051                         }
12052                         case CEE_MONO_JIT_ATTACH: {
12053                                 MonoInst *args [16], *domain_ins;
12054                                 MonoInst *ad_ins, *jit_tls_ins;
12055                                 MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
12056
12057                                 g_assert (!mono_threads_is_coop_enabled ());
12058
12059                                 cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12060
12061                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12062                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12063
12064                                 ad_ins = mono_get_domain_intrinsic (cfg);
12065                                 jit_tls_ins = mono_get_jit_tls_intrinsic (cfg);
12066
12067                                 if (cfg->backend->have_tls_get && ad_ins && jit_tls_ins) {
12068                                         NEW_BBLOCK (cfg, next_bb);
12069                                         NEW_BBLOCK (cfg, call_bb);
12070
12071                                         if (cfg->compile_aot) {
12072                                                 /* AOT code is only used in the root domain */
12073                                                 EMIT_NEW_PCONST (cfg, domain_ins, NULL);
12074                                         } else {
12075                                                 EMIT_NEW_PCONST (cfg, domain_ins, cfg->domain);
12076                                         }
12077                                         MONO_ADD_INS (cfg->cbb, ad_ins);
12078                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg);
12079                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb);
12080
12081                                         MONO_ADD_INS (cfg->cbb, jit_tls_ins);
12082                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0);
12083                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb);
12084
12085                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb);
12086                                         MONO_START_BB (cfg, call_bb);
12087                                 }
12088
12089                                 /* AOT code is only used in the root domain */
12090                                 EMIT_NEW_PCONST (cfg, args [0], cfg->compile_aot ? NULL : cfg->domain);
12091                                 if (cfg->compile_aot) {
12092                                         MonoInst *addr;
12093
12094                                         /*
12095                                          * This is called on unattached threads, so it cannot go through the trampoline
12096                                          * infrastructure. Use an indirect call through a got slot initialized at load time
12097                                          * instead.
12098                                          */
12099                                         EMIT_NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_JIT_THREAD_ATTACH, NULL);
12100                                         ins = mono_emit_calli (cfg, helper_sig_jit_thread_attach, args, addr, NULL, NULL);
12101                                 } else {
12102                                         ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
12103                                 }
12104                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12105
12106                                 if (next_bb)
12107                                         MONO_START_BB (cfg, next_bb);
12108
12109                                 ip += 2;
12110                                 break;
12111                         }
12112                         case CEE_MONO_JIT_DETACH: {
12113                                 MonoInst *args [16];
12114
12115                                 /* Restore the original domain */
12116                                 dreg = alloc_ireg (cfg);
12117                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->orig_domain_var->dreg);
12118                                 mono_emit_jit_icall (cfg, mono_jit_set_domain, args);
12119                                 ip += 2;
12120                                 break;
12121                         }
12122                         case CEE_MONO_CALLI_EXTRA_ARG: {
12123                                 MonoInst *addr;
12124                                 MonoMethodSignature *fsig;
12125                                 MonoInst *arg;
12126
12127                                 /*
12128                                  * This is the same as CEE_CALLI, but passes an additional argument
12129                                  * to the called method in llvmonly mode.
12130                                  * This is only used by delegate invoke wrappers to call the
12131                                  * actual delegate method.
12132                                  */
12133                                 g_assert (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE);
12134
12135                                 CHECK_OPSIZE (6);
12136                                 token = read32 (ip + 2);
12137
12138                                 ins = NULL;
12139
12140                                 cmethod = NULL;
12141                                 CHECK_STACK (1);
12142                                 --sp;
12143                                 addr = *sp;
12144                                 fsig = mini_get_signature (method, token, generic_context, &cfg->error);
12145                                 CHECK_CFG_ERROR;
12146
12147                                 if (cfg->llvm_only)
12148                                         cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
12149
12150                                 n = fsig->param_count + fsig->hasthis + 1;
12151
12152                                 CHECK_STACK (n);
12153
12154                                 sp -= n;
12155                                 arg = sp [n - 1];
12156
12157                                 if (cfg->llvm_only) {
12158                                         /*
12159                                          * The lowest bit of 'arg' determines whenever the callee uses the gsharedvt
12160                                          * cconv. This is set by mono_init_delegate ().
12161                                          */
12162                                         if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig)) {
12163                                                 MonoInst *callee = addr;
12164                                                 MonoInst *call, *localloc_ins;
12165                                                 MonoBasicBlock *is_gsharedvt_bb, *end_bb;
12166                                                 int low_bit_reg = alloc_preg (cfg);
12167
12168                                                 NEW_BBLOCK (cfg, is_gsharedvt_bb);
12169                                                 NEW_BBLOCK (cfg, end_bb);
12170
12171                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
12172                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
12173                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
12174
12175                                                 /* Normal case: callee uses a normal cconv, have to add an out wrapper */
12176                                                 addr = emit_get_rgctx_sig (cfg, context_used,
12177                                                                                                    fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
12178                                                 /*
12179                                                  * ADDR points to a gsharedvt-out wrapper, have to pass <callee, arg> as an extra arg.
12180                                                  */
12181                                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
12182                                                 ins->dreg = alloc_preg (cfg);
12183                                                 ins->inst_imm = 2 * SIZEOF_VOID_P;
12184                                                 MONO_ADD_INS (cfg->cbb, ins);
12185                                                 localloc_ins = ins;
12186                                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12187                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
12188                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
12189
12190                                                 call = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
12191                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12192
12193                                                 /* Gsharedvt case: callee uses a gsharedvt cconv, no conversion is needed */
12194                                                 MONO_START_BB (cfg, is_gsharedvt_bb);
12195                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
12196                                                 ins = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
12197                                                 ins->dreg = call->dreg;
12198
12199                                                 MONO_START_BB (cfg, end_bb);
12200                                         } else {
12201                                                 /* Caller uses a normal calling conv */
12202
12203                                                 MonoInst *callee = addr;
12204                                                 MonoInst *call, *localloc_ins;
12205                                                 MonoBasicBlock *is_gsharedvt_bb, *end_bb;
12206                                                 int low_bit_reg = alloc_preg (cfg);
12207
12208                                                 NEW_BBLOCK (cfg, is_gsharedvt_bb);
12209                                                 NEW_BBLOCK (cfg, end_bb);
12210
12211                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
12212                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
12213                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
12214
12215                                                 /* Normal case: callee uses a normal cconv, no conversion is needed */
12216                                                 call = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
12217                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12218                                                 /* Gsharedvt case: callee uses a gsharedvt cconv, have to add an in wrapper */
12219                                                 MONO_START_BB (cfg, is_gsharedvt_bb);
12220                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
12221                                                 NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER, fsig);
12222                                                 MONO_ADD_INS (cfg->cbb, addr);
12223                                                 /*
12224                                                  * ADDR points to a gsharedvt-in wrapper, have to pass <callee, arg> as an extra arg.
12225                                                  */
12226                                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
12227                                                 ins->dreg = alloc_preg (cfg);
12228                                                 ins->inst_imm = 2 * SIZEOF_VOID_P;
12229                                                 MONO_ADD_INS (cfg->cbb, ins);
12230                                                 localloc_ins = ins;
12231                                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12232                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
12233                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
12234
12235                                                 ins = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
12236                                                 ins->dreg = call->dreg;
12237                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12238
12239                                                 MONO_START_BB (cfg, end_bb);
12240                                         }
12241                                 } else {
12242                                         /* Same as CEE_CALLI */
12243                                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
12244                                                 /*
12245                                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
12246                                                  */
12247                                                 MonoInst *callee = addr;
12248
12249                                                 addr = emit_get_rgctx_sig (cfg, context_used,
12250                                                                                                    fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
12251                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
12252                                         } else {
12253                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
12254                                         }
12255                                 }
12256
12257                                 if (!MONO_TYPE_IS_VOID (fsig->ret))
12258                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
12259
12260                                 CHECK_CFG_EXCEPTION;
12261
12262                                 ip += 6;
12263                                 ins_flag = 0;
12264                                 constrained_class = NULL;
12265                                 break;
12266                         }
12267                         case CEE_MONO_LDDOMAIN:
12268                                 CHECK_STACK_OVF (1);
12269                                 EMIT_NEW_PCONST (cfg, ins, cfg->compile_aot ? NULL : cfg->domain);
12270                                 ip += 2;
12271                                 *sp++ = ins;
12272                                 break;
12273                         case CEE_MONO_GET_LAST_ERROR:
12274                                 CHECK_OPSIZE (2);
12275                                 CHECK_STACK_OVF (1);
12276
12277                                 MONO_INST_NEW (cfg, ins, OP_GET_LAST_ERROR);
12278                                 ins->dreg = alloc_dreg (cfg, STACK_I4);
12279                                 ins->type = STACK_I4;
12280                                 MONO_ADD_INS (cfg->cbb, ins);
12281
12282                                 ip += 2;
12283                                 *sp++ = ins;
12284                                 break;
12285                         default:
12286                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
12287                                 break;
12288                         }
12289                         break;
12290                 }
12291
12292                 case CEE_PREFIX1: {
12293                         CHECK_OPSIZE (2);
12294                         switch (ip [1]) {
12295                         case CEE_ARGLIST: {
12296                                 /* somewhat similar to LDTOKEN */
12297                                 MonoInst *addr, *vtvar;
12298                                 CHECK_STACK_OVF (1);
12299                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
12300
12301                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12302                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
12303
12304                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12305                                 ins->type = STACK_VTYPE;
12306                                 ins->klass = mono_defaults.argumenthandle_class;
12307                                 *sp++ = ins;
12308                                 ip += 2;
12309                                 break;
12310                         }
12311                         case CEE_CEQ:
12312                         case CEE_CGT:
12313                         case CEE_CGT_UN:
12314                         case CEE_CLT:
12315                         case CEE_CLT_UN: {
12316                                 MonoInst *cmp, *arg1, *arg2;
12317
12318                                 CHECK_STACK (2);
12319                                 sp -= 2;
12320                                 arg1 = sp [0];
12321                                 arg2 = sp [1];
12322
12323                                 /*
12324                                  * The following transforms:
12325                                  *    CEE_CEQ    into OP_CEQ
12326                                  *    CEE_CGT    into OP_CGT
12327                                  *    CEE_CGT_UN into OP_CGT_UN
12328                                  *    CEE_CLT    into OP_CLT
12329                                  *    CEE_CLT_UN into OP_CLT_UN
12330                                  */
12331                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
12332
12333                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
12334                                 cmp->sreg1 = arg1->dreg;
12335                                 cmp->sreg2 = arg2->dreg;
12336                                 type_from_op (cfg, cmp, arg1, arg2);
12337                                 CHECK_TYPE (cmp);
12338                                 add_widen_op (cfg, cmp, &arg1, &arg2);
12339                                 if ((arg1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((arg1->type == STACK_PTR) || (arg1->type == STACK_OBJ) || (arg1->type == STACK_MP))))
12340                                         cmp->opcode = OP_LCOMPARE;
12341                                 else if (arg1->type == STACK_R4)
12342                                         cmp->opcode = OP_RCOMPARE;
12343                                 else if (arg1->type == STACK_R8)
12344                                         cmp->opcode = OP_FCOMPARE;
12345                                 else
12346                                         cmp->opcode = OP_ICOMPARE;
12347                                 MONO_ADD_INS (cfg->cbb, cmp);
12348                                 ins->type = STACK_I4;
12349                                 ins->dreg = alloc_dreg (cfg, (MonoStackType)ins->type);
12350                                 type_from_op (cfg, ins, arg1, arg2);
12351
12352                                 if (cmp->opcode == OP_FCOMPARE || cmp->opcode == OP_RCOMPARE) {
12353                                         /*
12354                                          * The backends expect the fceq opcodes to do the
12355                                          * comparison too.
12356                                          */
12357                                         ins->sreg1 = cmp->sreg1;
12358                                         ins->sreg2 = cmp->sreg2;
12359                                         NULLIFY_INS (cmp);
12360                                 }
12361                                 MONO_ADD_INS (cfg->cbb, ins);
12362                                 *sp++ = ins;
12363                                 ip += 2;
12364                                 break;
12365                         }
12366                         case CEE_LDFTN: {
12367                                 MonoInst *argconst;
12368                                 MonoMethod *cil_method;
12369
12370                                 CHECK_STACK_OVF (1);
12371                                 CHECK_OPSIZE (6);
12372                                 n = read32 (ip + 2);
12373                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12374                                 CHECK_CFG_ERROR;
12375
12376                                 mono_class_init (cmethod->klass);
12377
12378                                 mono_save_token_info (cfg, image, n, cmethod);
12379
12380                                 context_used = mini_method_check_context_used (cfg, cmethod);
12381
12382                                 cil_method = cmethod;
12383                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
12384                                         emit_method_access_failure (cfg, method, cil_method);
12385
12386                                 if (mono_security_core_clr_enabled ())
12387                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
12388
12389                                 /* 
12390                                  * Optimize the common case of ldftn+delegate creation
12391                                  */
12392                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
12393                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12394                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12395                                                 MonoInst *target_ins, *handle_ins;
12396                                                 MonoMethod *invoke;
12397                                                 int invoke_context_used;
12398
12399                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12400                                                 if (!invoke || !mono_method_signature (invoke))
12401                                                         LOAD_ERROR;
12402
12403                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12404
12405                                                 target_ins = sp [-1];
12406
12407                                                 if (mono_security_core_clr_enabled ())
12408                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
12409
12410                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
12411                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
12412                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
12413                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
12414                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
12415                                                         }
12416                                                 }
12417
12418                                                 /* FIXME: SGEN support */
12419                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
12420                                                         ip += 6;
12421                                                         if (cfg->verbose_level > 3)
12422                                                                 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));
12423                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, FALSE))) {
12424                                                                 sp --;
12425                                                                 *sp = handle_ins;
12426                                                                 CHECK_CFG_EXCEPTION;
12427                                                                 ip += 5;
12428                                                                 sp ++;
12429                                                                 break;
12430                                                         }
12431                                                         ip -= 6;
12432                                                 }
12433                                         }
12434                                 }
12435
12436                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
12437                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
12438                                 *sp++ = ins;
12439                                 
12440                                 ip += 6;
12441                                 inline_costs += 10 * num_calls++;
12442                                 break;
12443                         }
12444                         case CEE_LDVIRTFTN: {
12445                                 MonoInst *args [2];
12446
12447                                 CHECK_STACK (1);
12448                                 CHECK_OPSIZE (6);
12449                                 n = read32 (ip + 2);
12450                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12451                                 CHECK_CFG_ERROR;
12452
12453                                 mono_class_init (cmethod->klass);
12454  
12455                                 context_used = mini_method_check_context_used (cfg, cmethod);
12456
12457                                 if (mono_security_core_clr_enabled ())
12458                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
12459
12460                                 /*
12461                                  * Optimize the common case of ldvirtftn+delegate creation
12462                                  */
12463                                 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)) {
12464                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12465                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12466                                                 MonoInst *target_ins, *handle_ins;
12467                                                 MonoMethod *invoke;
12468                                                 int invoke_context_used;
12469                                                 gboolean is_virtual = cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL;
12470
12471                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12472                                                 if (!invoke || !mono_method_signature (invoke))
12473                                                         LOAD_ERROR;
12474
12475                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12476
12477                                                 target_ins = sp [-1];
12478
12479                                                 if (mono_security_core_clr_enabled ())
12480                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
12481
12482                                                 /* FIXME: SGEN support */
12483                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
12484                                                         ip += 6;
12485                                                         if (cfg->verbose_level > 3)
12486                                                                 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));
12487                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, is_virtual))) {
12488                                                                 sp -= 2;
12489                                                                 *sp = handle_ins;
12490                                                                 CHECK_CFG_EXCEPTION;
12491                                                                 ip += 5;
12492                                                                 sp ++;
12493                                                                 break;
12494                                                         }
12495                                                         ip -= 6;
12496                                                 }
12497                                         }
12498                                 }
12499
12500                                 --sp;
12501                                 args [0] = *sp;
12502
12503                                 args [1] = emit_get_rgctx_method (cfg, context_used,
12504                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
12505
12506                                 if (context_used)
12507                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
12508                                 else
12509                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
12510
12511                                 ip += 6;
12512                                 inline_costs += 10 * num_calls++;
12513                                 break;
12514                         }
12515                         case CEE_LDARG:
12516                                 CHECK_STACK_OVF (1);
12517                                 CHECK_OPSIZE (4);
12518                                 n = read16 (ip + 2);
12519                                 CHECK_ARG (n);
12520                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
12521                                 *sp++ = ins;
12522                                 ip += 4;
12523                                 break;
12524                         case CEE_LDARGA:
12525                                 CHECK_STACK_OVF (1);
12526                                 CHECK_OPSIZE (4);
12527                                 n = read16 (ip + 2);
12528                                 CHECK_ARG (n);
12529                                 NEW_ARGLOADA (cfg, ins, n);
12530                                 MONO_ADD_INS (cfg->cbb, ins);
12531                                 *sp++ = ins;
12532                                 ip += 4;
12533                                 break;
12534                         case CEE_STARG:
12535                                 CHECK_STACK (1);
12536                                 --sp;
12537                                 CHECK_OPSIZE (4);
12538                                 n = read16 (ip + 2);
12539                                 CHECK_ARG (n);
12540                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
12541                                         UNVERIFIED;
12542                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
12543                                 ip += 4;
12544                                 break;
12545                         case CEE_LDLOC:
12546                                 CHECK_STACK_OVF (1);
12547                                 CHECK_OPSIZE (4);
12548                                 n = read16 (ip + 2);
12549                                 CHECK_LOCAL (n);
12550                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
12551                                 *sp++ = ins;
12552                                 ip += 4;
12553                                 break;
12554                         case CEE_LDLOCA: {
12555                                 unsigned char *tmp_ip;
12556                                 CHECK_STACK_OVF (1);
12557                                 CHECK_OPSIZE (4);
12558                                 n = read16 (ip + 2);
12559                                 CHECK_LOCAL (n);
12560
12561                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
12562                                         ip = tmp_ip;
12563                                         inline_costs += 1;
12564                                         break;
12565                                 }                       
12566                                 
12567                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
12568                                 *sp++ = ins;
12569                                 ip += 4;
12570                                 break;
12571                         }
12572                         case CEE_STLOC:
12573                                 CHECK_STACK (1);
12574                                 --sp;
12575                                 CHECK_OPSIZE (4);
12576                                 n = read16 (ip + 2);
12577                                 CHECK_LOCAL (n);
12578                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
12579                                         UNVERIFIED;
12580                                 emit_stloc_ir (cfg, sp, header, n);
12581                                 ip += 4;
12582                                 inline_costs += 1;
12583                                 break;
12584                         case CEE_LOCALLOC: {
12585                                 CHECK_STACK (1);
12586                                 MonoBasicBlock *non_zero_bb, *end_bb;
12587                                 int alloc_ptr = alloc_preg (cfg);
12588                                 --sp;
12589                                 if (sp != stack_start) 
12590                                         UNVERIFIED;
12591                                 if (cfg->method != method) 
12592                                         /* 
12593                                          * Inlining this into a loop in a parent could lead to 
12594                                          * stack overflows which is different behavior than the
12595                                          * non-inlined case, thus disable inlining in this case.
12596                                          */
12597                                         INLINE_FAILURE("localloc");
12598
12599                                 NEW_BBLOCK (cfg, non_zero_bb);
12600                                 NEW_BBLOCK (cfg, end_bb);
12601
12602                                 /* if size != zero */
12603                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
12604                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, non_zero_bb);
12605
12606                                 //size is zero, so result is NULL
12607                                 MONO_EMIT_NEW_PCONST (cfg, alloc_ptr, NULL);
12608                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12609
12610                                 MONO_START_BB (cfg, non_zero_bb);
12611                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
12612                                 ins->dreg = alloc_ptr;
12613                                 ins->sreg1 = sp [0]->dreg;
12614                                 ins->type = STACK_PTR;
12615                                 MONO_ADD_INS (cfg->cbb, ins);
12616
12617                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12618                                 if (init_locals)
12619                                         ins->flags |= MONO_INST_INIT;
12620
12621                                 MONO_START_BB (cfg, end_bb);
12622                                 EMIT_NEW_UNALU (cfg, ins, OP_MOVE, alloc_preg (cfg), alloc_ptr);
12623                                 ins->type = STACK_PTR;
12624
12625                                 *sp++ = ins;
12626                                 ip += 2;
12627                                 break;
12628                         }
12629                         case CEE_ENDFILTER: {
12630                                 MonoExceptionClause *clause, *nearest;
12631                                 int cc;
12632
12633                                 CHECK_STACK (1);
12634                                 --sp;
12635                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
12636                                         UNVERIFIED;
12637                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
12638                                 ins->sreg1 = (*sp)->dreg;
12639                                 MONO_ADD_INS (cfg->cbb, ins);
12640                                 start_new_bblock = 1;
12641                                 ip += 2;
12642
12643                                 nearest = NULL;
12644                                 for (cc = 0; cc < header->num_clauses; ++cc) {
12645                                         clause = &header->clauses [cc];
12646                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
12647                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
12648                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset)))
12649                                                 nearest = clause;
12650                                 }
12651                                 g_assert (nearest);
12652                                 if ((ip - header->code) != nearest->handler_offset)
12653                                         UNVERIFIED;
12654
12655                                 break;
12656                         }
12657                         case CEE_UNALIGNED_:
12658                                 ins_flag |= MONO_INST_UNALIGNED;
12659                                 /* FIXME: record alignment? we can assume 1 for now */
12660                                 CHECK_OPSIZE (3);
12661                                 ip += 3;
12662                                 break;
12663                         case CEE_VOLATILE_:
12664                                 ins_flag |= MONO_INST_VOLATILE;
12665                                 ip += 2;
12666                                 break;
12667                         case CEE_TAIL_:
12668                                 ins_flag   |= MONO_INST_TAILCALL;
12669                                 cfg->flags |= MONO_CFG_HAS_TAIL;
12670                                 /* Can't inline tail calls at this time */
12671                                 inline_costs += 100000;
12672                                 ip += 2;
12673                                 break;
12674                         case CEE_INITOBJ:
12675                                 CHECK_STACK (1);
12676                                 --sp;
12677                                 CHECK_OPSIZE (6);
12678                                 token = read32 (ip + 2);
12679                                 klass = mini_get_class (method, token, generic_context);
12680                                 CHECK_TYPELOAD (klass);
12681                                 if (generic_class_is_reference_type (cfg, klass))
12682                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
12683                                 else
12684                                         mini_emit_initobj (cfg, *sp, NULL, klass);
12685                                 ip += 6;
12686                                 inline_costs += 1;
12687                                 break;
12688                         case CEE_CONSTRAINED_:
12689                                 CHECK_OPSIZE (6);
12690                                 token = read32 (ip + 2);
12691                                 constrained_class = mini_get_class (method, token, generic_context);
12692                                 CHECK_TYPELOAD (constrained_class);
12693                                 ip += 6;
12694                                 break;
12695                         case CEE_CPBLK:
12696                         case CEE_INITBLK: {
12697                                 MonoInst *iargs [3];
12698                                 CHECK_STACK (3);
12699                                 sp -= 3;
12700
12701                                 /* Skip optimized paths for volatile operations. */
12702                                 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)) {
12703                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
12704                                 } 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)) {
12705                                         /* emit_memset only works when val == 0 */
12706                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
12707                                 } else {
12708                                         MonoInst *call;
12709                                         iargs [0] = sp [0];
12710                                         iargs [1] = sp [1];
12711                                         iargs [2] = sp [2];
12712                                         if (ip [1] == CEE_CPBLK) {
12713                                                 /*
12714                                                  * FIXME: It's unclear whether we should be emitting both the acquire
12715                                                  * and release barriers for cpblk. It is technically both a load and
12716                                                  * store operation, so it seems like that's the sensible thing to do.
12717                                                  *
12718                                                  * FIXME: We emit full barriers on both sides of the operation for
12719                                                  * simplicity. We should have a separate atomic memcpy method instead.
12720                                                  */
12721                                                 MonoMethod *memcpy_method = get_memcpy_method ();
12722
12723                                                 if (ins_flag & MONO_INST_VOLATILE)
12724                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12725
12726                                                 call = mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
12727                                                 call->flags |= ins_flag;
12728
12729                                                 if (ins_flag & MONO_INST_VOLATILE)
12730                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12731                                         } else {
12732                                                 MonoMethod *memset_method = get_memset_method ();
12733                                                 if (ins_flag & MONO_INST_VOLATILE) {
12734                                                         /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
12735                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
12736                                                 }
12737                                                 call = mono_emit_method_call (cfg, memset_method, iargs, NULL);
12738                                                 call->flags |= ins_flag;
12739                                         }
12740                                 }
12741                                 ip += 2;
12742                                 ins_flag = 0;
12743                                 inline_costs += 1;
12744                                 break;
12745                         }
12746                         case CEE_NO_:
12747                                 CHECK_OPSIZE (3);
12748                                 if (ip [2] & 0x1)
12749                                         ins_flag |= MONO_INST_NOTYPECHECK;
12750                                 if (ip [2] & 0x2)
12751                                         ins_flag |= MONO_INST_NORANGECHECK;
12752                                 /* we ignore the no-nullcheck for now since we
12753                                  * really do it explicitly only when doing callvirt->call
12754                                  */
12755                                 ip += 3;
12756                                 break;
12757                         case CEE_RETHROW: {
12758                                 MonoInst *load;
12759                                 int handler_offset = -1;
12760
12761                                 for (i = 0; i < header->num_clauses; ++i) {
12762                                         MonoExceptionClause *clause = &header->clauses [i];
12763                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
12764                                                 handler_offset = clause->handler_offset;
12765                                                 break;
12766                                         }
12767                                 }
12768
12769                                 cfg->cbb->flags |= BB_EXCEPTION_UNSAFE;
12770
12771                                 if (handler_offset == -1)
12772                                         UNVERIFIED;
12773
12774                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
12775                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
12776                                 ins->sreg1 = load->dreg;
12777                                 MONO_ADD_INS (cfg->cbb, ins);
12778
12779                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
12780                                 MONO_ADD_INS (cfg->cbb, ins);
12781
12782                                 sp = stack_start;
12783                                 link_bblock (cfg, cfg->cbb, end_bblock);
12784                                 start_new_bblock = 1;
12785                                 ip += 2;
12786                                 break;
12787                         }
12788                         case CEE_SIZEOF: {
12789                                 guint32 val;
12790                                 int ialign;
12791
12792                                 CHECK_STACK_OVF (1);
12793                                 CHECK_OPSIZE (6);
12794                                 token = read32 (ip + 2);
12795                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !image_is_dynamic (method->klass->image) && !generic_context) {
12796                                         MonoType *type = mono_type_create_from_typespec_checked (image, token, &cfg->error);
12797                                         CHECK_CFG_ERROR;
12798
12799                                         val = mono_type_size (type, &ialign);
12800                                 } else {
12801                                         MonoClass *klass = mini_get_class (method, token, generic_context);
12802                                         CHECK_TYPELOAD (klass);
12803
12804                                         val = mono_type_size (&klass->byval_arg, &ialign);
12805
12806                                         if (mini_is_gsharedvt_klass (klass))
12807                                                 GSHAREDVT_FAILURE (*ip);
12808                                 }
12809                                 EMIT_NEW_ICONST (cfg, ins, val);
12810                                 *sp++= ins;
12811                                 ip += 6;
12812                                 break;
12813                         }
12814                         case CEE_REFANYTYPE: {
12815                                 MonoInst *src_var, *src;
12816
12817                                 GSHAREDVT_FAILURE (*ip);
12818
12819                                 CHECK_STACK (1);
12820                                 --sp;
12821
12822                                 // FIXME:
12823                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12824                                 if (!src_var)
12825                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
12826                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
12827                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type));
12828                                 *sp++ = ins;
12829                                 ip += 2;
12830                                 break;
12831                         }
12832                         case CEE_READONLY_:
12833                                 readonly = TRUE;
12834                                 ip += 2;
12835                                 break;
12836
12837                         case CEE_UNUSED56:
12838                         case CEE_UNUSED57:
12839                         case CEE_UNUSED70:
12840                         case CEE_UNUSED:
12841                         case CEE_UNUSED99:
12842                                 UNVERIFIED;
12843                                 
12844                         default:
12845                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
12846                                 UNVERIFIED;
12847                         }
12848                         break;
12849                 }
12850                 case CEE_UNUSED58:
12851                 case CEE_UNUSED1:
12852                         UNVERIFIED;
12853
12854                 default:
12855                         g_warning ("opcode 0x%02x not handled", *ip);
12856                         UNVERIFIED;
12857                 }
12858         }
12859         if (start_new_bblock != 1)
12860                 UNVERIFIED;
12861
12862         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
12863         if (cfg->cbb->next_bb) {
12864                 /* This could already be set because of inlining, #693905 */
12865                 MonoBasicBlock *bb = cfg->cbb;
12866
12867                 while (bb->next_bb)
12868                         bb = bb->next_bb;
12869                 bb->next_bb = end_bblock;
12870         } else {
12871                 cfg->cbb->next_bb = end_bblock;
12872         }
12873
12874         if (cfg->method == method && cfg->domainvar) {
12875                 MonoInst *store;
12876                 MonoInst *get_domain;
12877
12878                 cfg->cbb = init_localsbb;
12879
12880                 if ((get_domain = mono_get_domain_intrinsic (cfg))) {
12881                         MONO_ADD_INS (cfg->cbb, get_domain);
12882                 } else {
12883                         get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
12884                 }
12885                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
12886                 MONO_ADD_INS (cfg->cbb, store);
12887         }
12888
12889 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
12890         if (cfg->compile_aot)
12891                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
12892                 mono_get_got_var (cfg);
12893 #endif
12894
12895         if (cfg->method == method && cfg->got_var)
12896                 mono_emit_load_got_addr (cfg);
12897
12898         if (init_localsbb) {
12899                 cfg->cbb = init_localsbb;
12900                 cfg->ip = NULL;
12901                 for (i = 0; i < header->num_locals; ++i) {
12902                         emit_init_local (cfg, i, header->locals [i], init_locals);
12903                 }
12904         }
12905
12906         if (cfg->init_ref_vars && cfg->method == method) {
12907                 /* Emit initialization for ref vars */
12908                 // FIXME: Avoid duplication initialization for IL locals.
12909                 for (i = 0; i < cfg->num_varinfo; ++i) {
12910                         MonoInst *ins = cfg->varinfo [i];
12911
12912                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
12913                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
12914                 }
12915         }
12916
12917         if (cfg->lmf_var && cfg->method == method && !cfg->llvm_only) {
12918                 cfg->cbb = init_localsbb;
12919                 emit_push_lmf (cfg);
12920         }
12921
12922         cfg->cbb = init_localsbb;
12923         emit_instrumentation_call (cfg, mono_profiler_method_enter);
12924
12925         if (seq_points) {
12926                 MonoBasicBlock *bb;
12927
12928                 /*
12929                  * Make seq points at backward branch targets interruptable.
12930                  */
12931                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
12932                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
12933                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
12934         }
12935
12936         /* Add a sequence point for method entry/exit events */
12937         if (seq_points && cfg->gen_sdb_seq_points) {
12938                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
12939                 MONO_ADD_INS (init_localsbb, ins);
12940                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
12941                 MONO_ADD_INS (cfg->bb_exit, ins);
12942         }
12943
12944         /*
12945          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
12946          * the code they refer to was dead (#11880).
12947          */
12948         if (sym_seq_points) {
12949                 for (i = 0; i < header->code_size; ++i) {
12950                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
12951                                 MonoInst *ins;
12952
12953                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
12954                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
12955                         }
12956                 }
12957         }
12958
12959         cfg->ip = NULL;
12960
12961         if (cfg->method == method) {
12962                 MonoBasicBlock *bb;
12963                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12964                         if (bb == cfg->bb_init)
12965                                 bb->region = -1;
12966                         else
12967                                 bb->region = mono_find_block_region (cfg, bb->real_offset);
12968                         if (cfg->spvars)
12969                                 mono_create_spvar_for_region (cfg, bb->region);
12970                         if (cfg->verbose_level > 2)
12971                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
12972                 }
12973         } else {
12974                 MonoBasicBlock *bb;
12975                 /* get_most_deep_clause () in mini-llvm.c depends on this for inlined bblocks */
12976                 for (bb = start_bblock; bb != end_bblock; bb  = bb->next_bb) {
12977                         bb->real_offset = inline_offset;
12978                 }
12979         }
12980
12981         if (inline_costs < 0) {
12982                 char *mname;
12983
12984                 /* Method is too large */
12985                 mname = mono_method_full_name (method, TRUE);
12986                 mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Method %s is too complex.", mname));
12987                 g_free (mname);
12988         }
12989
12990         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
12991                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
12992
12993         goto cleanup;
12994
12995 mono_error_exit:
12996         g_assert (!mono_error_ok (&cfg->error));
12997         goto cleanup;
12998  
12999  exception_exit:
13000         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
13001         goto cleanup;
13002
13003  unverified:
13004         set_exception_type_from_invalid_il (cfg, method, ip);
13005         goto cleanup;
13006
13007  cleanup:
13008         g_slist_free (class_inits);
13009         mono_basic_block_free (original_bb);
13010         cfg->dont_inline = g_list_remove (cfg->dont_inline, method);
13011         if (cfg->exception_type)
13012                 return -1;
13013         else
13014                 return inline_costs;
13015 }
13016
13017 static int
13018 store_membase_reg_to_store_membase_imm (int opcode)
13019 {
13020         switch (opcode) {
13021         case OP_STORE_MEMBASE_REG:
13022                 return OP_STORE_MEMBASE_IMM;
13023         case OP_STOREI1_MEMBASE_REG:
13024                 return OP_STOREI1_MEMBASE_IMM;
13025         case OP_STOREI2_MEMBASE_REG:
13026                 return OP_STOREI2_MEMBASE_IMM;
13027         case OP_STOREI4_MEMBASE_REG:
13028                 return OP_STOREI4_MEMBASE_IMM;
13029         case OP_STOREI8_MEMBASE_REG:
13030                 return OP_STOREI8_MEMBASE_IMM;
13031         default:
13032                 g_assert_not_reached ();
13033         }
13034
13035         return -1;
13036 }               
13037
13038 int
13039 mono_op_to_op_imm (int opcode)
13040 {
13041         switch (opcode) {
13042         case OP_IADD:
13043                 return OP_IADD_IMM;
13044         case OP_ISUB:
13045                 return OP_ISUB_IMM;
13046         case OP_IDIV:
13047                 return OP_IDIV_IMM;
13048         case OP_IDIV_UN:
13049                 return OP_IDIV_UN_IMM;
13050         case OP_IREM:
13051                 return OP_IREM_IMM;
13052         case OP_IREM_UN:
13053                 return OP_IREM_UN_IMM;
13054         case OP_IMUL:
13055                 return OP_IMUL_IMM;
13056         case OP_IAND:
13057                 return OP_IAND_IMM;
13058         case OP_IOR:
13059                 return OP_IOR_IMM;
13060         case OP_IXOR:
13061                 return OP_IXOR_IMM;
13062         case OP_ISHL:
13063                 return OP_ISHL_IMM;
13064         case OP_ISHR:
13065                 return OP_ISHR_IMM;
13066         case OP_ISHR_UN:
13067                 return OP_ISHR_UN_IMM;
13068
13069         case OP_LADD:
13070                 return OP_LADD_IMM;
13071         case OP_LSUB:
13072                 return OP_LSUB_IMM;
13073         case OP_LAND:
13074                 return OP_LAND_IMM;
13075         case OP_LOR:
13076                 return OP_LOR_IMM;
13077         case OP_LXOR:
13078                 return OP_LXOR_IMM;
13079         case OP_LSHL:
13080                 return OP_LSHL_IMM;
13081         case OP_LSHR:
13082                 return OP_LSHR_IMM;
13083         case OP_LSHR_UN:
13084                 return OP_LSHR_UN_IMM;
13085 #if SIZEOF_REGISTER == 8
13086         case OP_LREM:
13087                 return OP_LREM_IMM;
13088 #endif
13089
13090         case OP_COMPARE:
13091                 return OP_COMPARE_IMM;
13092         case OP_ICOMPARE:
13093                 return OP_ICOMPARE_IMM;
13094         case OP_LCOMPARE:
13095                 return OP_LCOMPARE_IMM;
13096
13097         case OP_STORE_MEMBASE_REG:
13098                 return OP_STORE_MEMBASE_IMM;
13099         case OP_STOREI1_MEMBASE_REG:
13100                 return OP_STOREI1_MEMBASE_IMM;
13101         case OP_STOREI2_MEMBASE_REG:
13102                 return OP_STOREI2_MEMBASE_IMM;
13103         case OP_STOREI4_MEMBASE_REG:
13104                 return OP_STOREI4_MEMBASE_IMM;
13105
13106 #if defined(TARGET_X86) || defined (TARGET_AMD64)
13107         case OP_X86_PUSH:
13108                 return OP_X86_PUSH_IMM;
13109         case OP_X86_COMPARE_MEMBASE_REG:
13110                 return OP_X86_COMPARE_MEMBASE_IMM;
13111 #endif
13112 #if defined(TARGET_AMD64)
13113         case OP_AMD64_ICOMPARE_MEMBASE_REG:
13114                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13115 #endif
13116         case OP_VOIDCALL_REG:
13117                 return OP_VOIDCALL;
13118         case OP_CALL_REG:
13119                 return OP_CALL;
13120         case OP_LCALL_REG:
13121                 return OP_LCALL;
13122         case OP_FCALL_REG:
13123                 return OP_FCALL;
13124         case OP_LOCALLOC:
13125                 return OP_LOCALLOC_IMM;
13126         }
13127
13128         return -1;
13129 }
13130
13131 static int
13132 ldind_to_load_membase (int opcode)
13133 {
13134         switch (opcode) {
13135         case CEE_LDIND_I1:
13136                 return OP_LOADI1_MEMBASE;
13137         case CEE_LDIND_U1:
13138                 return OP_LOADU1_MEMBASE;
13139         case CEE_LDIND_I2:
13140                 return OP_LOADI2_MEMBASE;
13141         case CEE_LDIND_U2:
13142                 return OP_LOADU2_MEMBASE;
13143         case CEE_LDIND_I4:
13144                 return OP_LOADI4_MEMBASE;
13145         case CEE_LDIND_U4:
13146                 return OP_LOADU4_MEMBASE;
13147         case CEE_LDIND_I:
13148                 return OP_LOAD_MEMBASE;
13149         case CEE_LDIND_REF:
13150                 return OP_LOAD_MEMBASE;
13151         case CEE_LDIND_I8:
13152                 return OP_LOADI8_MEMBASE;
13153         case CEE_LDIND_R4:
13154                 return OP_LOADR4_MEMBASE;
13155         case CEE_LDIND_R8:
13156                 return OP_LOADR8_MEMBASE;
13157         default:
13158                 g_assert_not_reached ();
13159         }
13160
13161         return -1;
13162 }
13163
13164 static int
13165 stind_to_store_membase (int opcode)
13166 {
13167         switch (opcode) {
13168         case CEE_STIND_I1:
13169                 return OP_STOREI1_MEMBASE_REG;
13170         case CEE_STIND_I2:
13171                 return OP_STOREI2_MEMBASE_REG;
13172         case CEE_STIND_I4:
13173                 return OP_STOREI4_MEMBASE_REG;
13174         case CEE_STIND_I:
13175         case CEE_STIND_REF:
13176                 return OP_STORE_MEMBASE_REG;
13177         case CEE_STIND_I8:
13178                 return OP_STOREI8_MEMBASE_REG;
13179         case CEE_STIND_R4:
13180                 return OP_STORER4_MEMBASE_REG;
13181         case CEE_STIND_R8:
13182                 return OP_STORER8_MEMBASE_REG;
13183         default:
13184                 g_assert_not_reached ();
13185         }
13186
13187         return -1;
13188 }
13189
13190 int
13191 mono_load_membase_to_load_mem (int opcode)
13192 {
13193         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
13194 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13195         switch (opcode) {
13196         case OP_LOAD_MEMBASE:
13197                 return OP_LOAD_MEM;
13198         case OP_LOADU1_MEMBASE:
13199                 return OP_LOADU1_MEM;
13200         case OP_LOADU2_MEMBASE:
13201                 return OP_LOADU2_MEM;
13202         case OP_LOADI4_MEMBASE:
13203                 return OP_LOADI4_MEM;
13204         case OP_LOADU4_MEMBASE:
13205                 return OP_LOADU4_MEM;
13206 #if SIZEOF_REGISTER == 8
13207         case OP_LOADI8_MEMBASE:
13208                 return OP_LOADI8_MEM;
13209 #endif
13210         }
13211 #endif
13212
13213         return -1;
13214 }
13215
13216 static inline int
13217 op_to_op_dest_membase (int store_opcode, int opcode)
13218 {
13219 #if defined(TARGET_X86)
13220         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
13221                 return -1;
13222
13223         switch (opcode) {
13224         case OP_IADD:
13225                 return OP_X86_ADD_MEMBASE_REG;
13226         case OP_ISUB:
13227                 return OP_X86_SUB_MEMBASE_REG;
13228         case OP_IAND:
13229                 return OP_X86_AND_MEMBASE_REG;
13230         case OP_IOR:
13231                 return OP_X86_OR_MEMBASE_REG;
13232         case OP_IXOR:
13233                 return OP_X86_XOR_MEMBASE_REG;
13234         case OP_ADD_IMM:
13235         case OP_IADD_IMM:
13236                 return OP_X86_ADD_MEMBASE_IMM;
13237         case OP_SUB_IMM:
13238         case OP_ISUB_IMM:
13239                 return OP_X86_SUB_MEMBASE_IMM;
13240         case OP_AND_IMM:
13241         case OP_IAND_IMM:
13242                 return OP_X86_AND_MEMBASE_IMM;
13243         case OP_OR_IMM:
13244         case OP_IOR_IMM:
13245                 return OP_X86_OR_MEMBASE_IMM;
13246         case OP_XOR_IMM:
13247         case OP_IXOR_IMM:
13248                 return OP_X86_XOR_MEMBASE_IMM;
13249         case OP_MOVE:
13250                 return OP_NOP;
13251         }
13252 #endif
13253
13254 #if defined(TARGET_AMD64)
13255         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
13256                 return -1;
13257
13258         switch (opcode) {
13259         case OP_IADD:
13260                 return OP_X86_ADD_MEMBASE_REG;
13261         case OP_ISUB:
13262                 return OP_X86_SUB_MEMBASE_REG;
13263         case OP_IAND:
13264                 return OP_X86_AND_MEMBASE_REG;
13265         case OP_IOR:
13266                 return OP_X86_OR_MEMBASE_REG;
13267         case OP_IXOR:
13268                 return OP_X86_XOR_MEMBASE_REG;
13269         case OP_IADD_IMM:
13270                 return OP_X86_ADD_MEMBASE_IMM;
13271         case OP_ISUB_IMM:
13272                 return OP_X86_SUB_MEMBASE_IMM;
13273         case OP_IAND_IMM:
13274                 return OP_X86_AND_MEMBASE_IMM;
13275         case OP_IOR_IMM:
13276                 return OP_X86_OR_MEMBASE_IMM;
13277         case OP_IXOR_IMM:
13278                 return OP_X86_XOR_MEMBASE_IMM;
13279         case OP_LADD:
13280                 return OP_AMD64_ADD_MEMBASE_REG;
13281         case OP_LSUB:
13282                 return OP_AMD64_SUB_MEMBASE_REG;
13283         case OP_LAND:
13284                 return OP_AMD64_AND_MEMBASE_REG;
13285         case OP_LOR:
13286                 return OP_AMD64_OR_MEMBASE_REG;
13287         case OP_LXOR:
13288                 return OP_AMD64_XOR_MEMBASE_REG;
13289         case OP_ADD_IMM:
13290         case OP_LADD_IMM:
13291                 return OP_AMD64_ADD_MEMBASE_IMM;
13292         case OP_SUB_IMM:
13293         case OP_LSUB_IMM:
13294                 return OP_AMD64_SUB_MEMBASE_IMM;
13295         case OP_AND_IMM:
13296         case OP_LAND_IMM:
13297                 return OP_AMD64_AND_MEMBASE_IMM;
13298         case OP_OR_IMM:
13299         case OP_LOR_IMM:
13300                 return OP_AMD64_OR_MEMBASE_IMM;
13301         case OP_XOR_IMM:
13302         case OP_LXOR_IMM:
13303                 return OP_AMD64_XOR_MEMBASE_IMM;
13304         case OP_MOVE:
13305                 return OP_NOP;
13306         }
13307 #endif
13308
13309         return -1;
13310 }
13311
13312 static inline int
13313 op_to_op_store_membase (int store_opcode, int opcode)
13314 {
13315 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13316         switch (opcode) {
13317         case OP_ICEQ:
13318                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13319                         return OP_X86_SETEQ_MEMBASE;
13320         case OP_CNE:
13321                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13322                         return OP_X86_SETNE_MEMBASE;
13323         }
13324 #endif
13325
13326         return -1;
13327 }
13328
13329 static inline int
13330 op_to_op_src1_membase (MonoCompile *cfg, int load_opcode, int opcode)
13331 {
13332 #ifdef TARGET_X86
13333         /* FIXME: This has sign extension issues */
13334         /*
13335         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13336                 return OP_X86_COMPARE_MEMBASE8_IMM;
13337         */
13338
13339         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13340                 return -1;
13341
13342         switch (opcode) {
13343         case OP_X86_PUSH:
13344                 return OP_X86_PUSH_MEMBASE;
13345         case OP_COMPARE_IMM:
13346         case OP_ICOMPARE_IMM:
13347                 return OP_X86_COMPARE_MEMBASE_IMM;
13348         case OP_COMPARE:
13349         case OP_ICOMPARE:
13350                 return OP_X86_COMPARE_MEMBASE_REG;
13351         }
13352 #endif
13353
13354 #ifdef TARGET_AMD64
13355         /* FIXME: This has sign extension issues */
13356         /*
13357         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13358                 return OP_X86_COMPARE_MEMBASE8_IMM;
13359         */
13360
13361         switch (opcode) {
13362         case OP_X86_PUSH:
13363                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
13364                         return OP_X86_PUSH_MEMBASE;
13365                 break;
13366                 /* FIXME: This only works for 32 bit immediates
13367         case OP_COMPARE_IMM:
13368         case OP_LCOMPARE_IMM:
13369                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13370                         return OP_AMD64_COMPARE_MEMBASE_IMM;
13371                 */
13372         case OP_ICOMPARE_IMM:
13373                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13374                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13375                 break;
13376         case OP_COMPARE:
13377         case OP_LCOMPARE:
13378                 if (cfg->backend->ilp32 && load_opcode == OP_LOAD_MEMBASE)
13379                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13380                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
13381                         return OP_AMD64_COMPARE_MEMBASE_REG;
13382                 break;
13383         case OP_ICOMPARE:
13384                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13385                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13386                 break;
13387         }
13388 #endif
13389
13390         return -1;
13391 }
13392
13393 static inline int
13394 op_to_op_src2_membase (MonoCompile *cfg, int load_opcode, int opcode)
13395 {
13396 #ifdef TARGET_X86
13397         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13398                 return -1;
13399         
13400         switch (opcode) {
13401         case OP_COMPARE:
13402         case OP_ICOMPARE:
13403                 return OP_X86_COMPARE_REG_MEMBASE;
13404         case OP_IADD:
13405                 return OP_X86_ADD_REG_MEMBASE;
13406         case OP_ISUB:
13407                 return OP_X86_SUB_REG_MEMBASE;
13408         case OP_IAND:
13409                 return OP_X86_AND_REG_MEMBASE;
13410         case OP_IOR:
13411                 return OP_X86_OR_REG_MEMBASE;
13412         case OP_IXOR:
13413                 return OP_X86_XOR_REG_MEMBASE;
13414         }
13415 #endif
13416
13417 #ifdef TARGET_AMD64
13418         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && cfg->backend->ilp32)) {
13419                 switch (opcode) {
13420                 case OP_ICOMPARE:
13421                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
13422                 case OP_IADD:
13423                         return OP_X86_ADD_REG_MEMBASE;
13424                 case OP_ISUB:
13425                         return OP_X86_SUB_REG_MEMBASE;
13426                 case OP_IAND:
13427                         return OP_X86_AND_REG_MEMBASE;
13428                 case OP_IOR:
13429                         return OP_X86_OR_REG_MEMBASE;
13430                 case OP_IXOR:
13431                         return OP_X86_XOR_REG_MEMBASE;
13432                 }
13433         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32)) {
13434                 switch (opcode) {
13435                 case OP_COMPARE:
13436                 case OP_LCOMPARE:
13437                         return OP_AMD64_COMPARE_REG_MEMBASE;
13438                 case OP_LADD:
13439                         return OP_AMD64_ADD_REG_MEMBASE;
13440                 case OP_LSUB:
13441                         return OP_AMD64_SUB_REG_MEMBASE;
13442                 case OP_LAND:
13443                         return OP_AMD64_AND_REG_MEMBASE;
13444                 case OP_LOR:
13445                         return OP_AMD64_OR_REG_MEMBASE;
13446                 case OP_LXOR:
13447                         return OP_AMD64_XOR_REG_MEMBASE;
13448                 }
13449         }
13450 #endif
13451
13452         return -1;
13453 }
13454
13455 int
13456 mono_op_to_op_imm_noemul (int opcode)
13457 {
13458         switch (opcode) {
13459 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
13460         case OP_LSHR:
13461         case OP_LSHL:
13462         case OP_LSHR_UN:
13463                 return -1;
13464 #endif
13465 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
13466         case OP_IDIV:
13467         case OP_IDIV_UN:
13468         case OP_IREM:
13469         case OP_IREM_UN:
13470                 return -1;
13471 #endif
13472 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
13473         case OP_IMUL:
13474                 return -1;
13475 #endif
13476         default:
13477                 return mono_op_to_op_imm (opcode);
13478         }
13479 }
13480
13481 /**
13482  * mono_handle_global_vregs:
13483  *
13484  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
13485  * for them.
13486  */
13487 void
13488 mono_handle_global_vregs (MonoCompile *cfg)
13489 {
13490         gint32 *vreg_to_bb;
13491         MonoBasicBlock *bb;
13492         int i, pos;
13493
13494         vreg_to_bb = (gint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
13495
13496 #ifdef MONO_ARCH_SIMD_INTRINSICS
13497         if (cfg->uses_simd_intrinsics)
13498                 mono_simd_simplify_indirection (cfg);
13499 #endif
13500
13501         /* Find local vregs used in more than one bb */
13502         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13503                 MonoInst *ins = bb->code;       
13504                 int block_num = bb->block_num;
13505
13506                 if (cfg->verbose_level > 2)
13507                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
13508
13509                 cfg->cbb = bb;
13510                 for (; ins; ins = ins->next) {
13511                         const char *spec = INS_INFO (ins->opcode);
13512                         int regtype = 0, regindex;
13513                         gint32 prev_bb;
13514
13515                         if (G_UNLIKELY (cfg->verbose_level > 2))
13516                                 mono_print_ins (ins);
13517
13518                         g_assert (ins->opcode >= MONO_CEE_LAST);
13519
13520                         for (regindex = 0; regindex < 4; regindex ++) {
13521                                 int vreg = 0;
13522
13523                                 if (regindex == 0) {
13524                                         regtype = spec [MONO_INST_DEST];
13525                                         if (regtype == ' ')
13526                                                 continue;
13527                                         vreg = ins->dreg;
13528                                 } else if (regindex == 1) {
13529                                         regtype = spec [MONO_INST_SRC1];
13530                                         if (regtype == ' ')
13531                                                 continue;
13532                                         vreg = ins->sreg1;
13533                                 } else if (regindex == 2) {
13534                                         regtype = spec [MONO_INST_SRC2];
13535                                         if (regtype == ' ')
13536                                                 continue;
13537                                         vreg = ins->sreg2;
13538                                 } else if (regindex == 3) {
13539                                         regtype = spec [MONO_INST_SRC3];
13540                                         if (regtype == ' ')
13541                                                 continue;
13542                                         vreg = ins->sreg3;
13543                                 }
13544
13545 #if SIZEOF_REGISTER == 4
13546                                 /* In the LLVM case, the long opcodes are not decomposed */
13547                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
13548                                         /*
13549                                          * Since some instructions reference the original long vreg,
13550                                          * and some reference the two component vregs, it is quite hard
13551                                          * to determine when it needs to be global. So be conservative.
13552                                          */
13553                                         if (!get_vreg_to_inst (cfg, vreg)) {
13554                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13555
13556                                                 if (cfg->verbose_level > 2)
13557                                                         printf ("LONG VREG R%d made global.\n", vreg);
13558                                         }
13559
13560                                         /*
13561                                          * Make the component vregs volatile since the optimizations can
13562                                          * get confused otherwise.
13563                                          */
13564                                         get_vreg_to_inst (cfg, MONO_LVREG_LS (vreg))->flags |= MONO_INST_VOLATILE;
13565                                         get_vreg_to_inst (cfg, MONO_LVREG_MS (vreg))->flags |= MONO_INST_VOLATILE;
13566                                 }
13567 #endif
13568
13569                                 g_assert (vreg != -1);
13570
13571                                 prev_bb = vreg_to_bb [vreg];
13572                                 if (prev_bb == 0) {
13573                                         /* 0 is a valid block num */
13574                                         vreg_to_bb [vreg] = block_num + 1;
13575                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
13576                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
13577                                                 continue;
13578
13579                                         if (!get_vreg_to_inst (cfg, vreg)) {
13580                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13581                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
13582
13583                                                 switch (regtype) {
13584                                                 case 'i':
13585                                                         if (vreg_is_ref (cfg, vreg))
13586                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
13587                                                         else
13588                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
13589                                                         break;
13590                                                 case 'l':
13591                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13592                                                         break;
13593                                                 case 'f':
13594                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
13595                                                         break;
13596                                                 case 'v':
13597                                                 case 'x':
13598                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
13599                                                         break;
13600                                                 default:
13601                                                         g_assert_not_reached ();
13602                                                 }
13603                                         }
13604
13605                                         /* Flag as having been used in more than one bb */
13606                                         vreg_to_bb [vreg] = -1;
13607                                 }
13608                         }
13609                 }
13610         }
13611
13612         /* If a variable is used in only one bblock, convert it into a local vreg */
13613         for (i = 0; i < cfg->num_varinfo; i++) {
13614                 MonoInst *var = cfg->varinfo [i];
13615                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
13616
13617                 switch (var->type) {
13618                 case STACK_I4:
13619                 case STACK_OBJ:
13620                 case STACK_PTR:
13621                 case STACK_MP:
13622                 case STACK_VTYPE:
13623 #if SIZEOF_REGISTER == 8
13624                 case STACK_I8:
13625 #endif
13626 #if !defined(TARGET_X86)
13627                 /* Enabling this screws up the fp stack on x86 */
13628                 case STACK_R8:
13629 #endif
13630                         if (mono_arch_is_soft_float ())
13631                                 break;
13632
13633                         /*
13634                         if (var->type == STACK_VTYPE && cfg->gsharedvt && mini_is_gsharedvt_variable_type (var->inst_vtype))
13635                                 break;
13636                         */
13637
13638                         /* Arguments are implicitly global */
13639                         /* Putting R4 vars into registers doesn't work currently */
13640                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
13641                         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) {
13642                                 /* 
13643                                  * Make that the variable's liveness interval doesn't contain a call, since
13644                                  * that would cause the lvreg to be spilled, making the whole optimization
13645                                  * useless.
13646                                  */
13647                                 /* This is too slow for JIT compilation */
13648 #if 0
13649                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
13650                                         MonoInst *ins;
13651                                         int def_index, call_index, ins_index;
13652                                         gboolean spilled = FALSE;
13653
13654                                         def_index = -1;
13655                                         call_index = -1;
13656                                         ins_index = 0;
13657                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
13658                                                 const char *spec = INS_INFO (ins->opcode);
13659
13660                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
13661                                                         def_index = ins_index;
13662
13663                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
13664                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
13665                                                         if (call_index > def_index) {
13666                                                                 spilled = TRUE;
13667                                                                 break;
13668                                                         }
13669                                                 }
13670
13671                                                 if (MONO_IS_CALL (ins))
13672                                                         call_index = ins_index;
13673
13674                                                 ins_index ++;
13675                                         }
13676
13677                                         if (spilled)
13678                                                 break;
13679                                 }
13680 #endif
13681
13682                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13683                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
13684                                 var->flags |= MONO_INST_IS_DEAD;
13685                                 cfg->vreg_to_inst [var->dreg] = NULL;
13686                         }
13687                         break;
13688                 }
13689         }
13690
13691         /* 
13692          * Compress the varinfo and vars tables so the liveness computation is faster and
13693          * takes up less space.
13694          */
13695         pos = 0;
13696         for (i = 0; i < cfg->num_varinfo; ++i) {
13697                 MonoInst *var = cfg->varinfo [i];
13698                 if (pos < i && cfg->locals_start == i)
13699                         cfg->locals_start = pos;
13700                 if (!(var->flags & MONO_INST_IS_DEAD)) {
13701                         if (pos < i) {
13702                                 cfg->varinfo [pos] = cfg->varinfo [i];
13703                                 cfg->varinfo [pos]->inst_c0 = pos;
13704                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
13705                                 cfg->vars [pos].idx = pos;
13706 #if SIZEOF_REGISTER == 4
13707                                 if (cfg->varinfo [pos]->type == STACK_I8) {
13708                                         /* Modify the two component vars too */
13709                                         MonoInst *var1;
13710
13711                                         var1 = get_vreg_to_inst (cfg, MONO_LVREG_LS (cfg->varinfo [pos]->dreg));
13712                                         var1->inst_c0 = pos;
13713                                         var1 = get_vreg_to_inst (cfg, MONO_LVREG_MS (cfg->varinfo [pos]->dreg));
13714                                         var1->inst_c0 = pos;
13715                                 }
13716 #endif
13717                         }
13718                         pos ++;
13719                 }
13720         }
13721         cfg->num_varinfo = pos;
13722         if (cfg->locals_start > cfg->num_varinfo)
13723                 cfg->locals_start = cfg->num_varinfo;
13724 }
13725
13726 /*
13727  * mono_allocate_gsharedvt_vars:
13728  *
13729  *   Allocate variables with gsharedvt types to entries in the MonoGSharedVtMethodRuntimeInfo.entries array.
13730  * Initialize cfg->gsharedvt_vreg_to_idx with the mapping between vregs and indexes.
13731  */
13732 void
13733 mono_allocate_gsharedvt_vars (MonoCompile *cfg)
13734 {
13735         int i;
13736
13737         cfg->gsharedvt_vreg_to_idx = (int *)mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
13738
13739         for (i = 0; i < cfg->num_varinfo; ++i) {
13740                 MonoInst *ins = cfg->varinfo [i];
13741                 int idx;
13742
13743                 if (mini_is_gsharedvt_variable_type (ins->inst_vtype)) {
13744                         if (i >= cfg->locals_start) {
13745                                 /* Local */
13746                                 idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
13747                                 cfg->gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
13748                                 ins->opcode = OP_GSHAREDVT_LOCAL;
13749                                 ins->inst_imm = idx;
13750                         } else {
13751                                 /* Arg */
13752                                 cfg->gsharedvt_vreg_to_idx [ins->dreg] = -1;
13753                                 ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
13754                         }
13755                 }
13756         }
13757 }
13758
13759 /**
13760  * mono_spill_global_vars:
13761  *
13762  *   Generate spill code for variables which are not allocated to registers, 
13763  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
13764  * code is generated which could be optimized by the local optimization passes.
13765  */
13766 void
13767 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
13768 {
13769         MonoBasicBlock *bb;
13770         char spec2 [16];
13771         int orig_next_vreg;
13772         guint32 *vreg_to_lvreg;
13773         guint32 *lvregs;
13774         guint32 i, lvregs_len;
13775         gboolean dest_has_lvreg = FALSE;
13776         MonoStackType stacktypes [128];
13777         MonoInst **live_range_start, **live_range_end;
13778         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
13779
13780         *need_local_opts = FALSE;
13781
13782         memset (spec2, 0, sizeof (spec2));
13783
13784         /* FIXME: Move this function to mini.c */
13785         stacktypes ['i'] = STACK_PTR;
13786         stacktypes ['l'] = STACK_I8;
13787         stacktypes ['f'] = STACK_R8;
13788 #ifdef MONO_ARCH_SIMD_INTRINSICS
13789         stacktypes ['x'] = STACK_VTYPE;
13790 #endif
13791
13792 #if SIZEOF_REGISTER == 4
13793         /* Create MonoInsts for longs */
13794         for (i = 0; i < cfg->num_varinfo; i++) {
13795                 MonoInst *ins = cfg->varinfo [i];
13796
13797                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
13798                         switch (ins->type) {
13799                         case STACK_R8:
13800                         case STACK_I8: {
13801                                 MonoInst *tree;
13802
13803                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
13804                                         break;
13805
13806                                 g_assert (ins->opcode == OP_REGOFFSET);
13807
13808                                 tree = get_vreg_to_inst (cfg, MONO_LVREG_LS (ins->dreg));
13809                                 g_assert (tree);
13810                                 tree->opcode = OP_REGOFFSET;
13811                                 tree->inst_basereg = ins->inst_basereg;
13812                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
13813
13814                                 tree = get_vreg_to_inst (cfg, MONO_LVREG_MS (ins->dreg));
13815                                 g_assert (tree);
13816                                 tree->opcode = OP_REGOFFSET;
13817                                 tree->inst_basereg = ins->inst_basereg;
13818                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
13819                                 break;
13820                         }
13821                         default:
13822                                 break;
13823                         }
13824                 }
13825         }
13826 #endif
13827
13828         if (cfg->compute_gc_maps) {
13829                 /* registers need liveness info even for !non refs */
13830                 for (i = 0; i < cfg->num_varinfo; i++) {
13831                         MonoInst *ins = cfg->varinfo [i];
13832
13833                         if (ins->opcode == OP_REGVAR)
13834                                 ins->flags |= MONO_INST_GC_TRACK;
13835                 }
13836         }
13837                 
13838         /* FIXME: widening and truncation */
13839
13840         /*
13841          * As an optimization, when a variable allocated to the stack is first loaded into 
13842          * an lvreg, we will remember the lvreg and use it the next time instead of loading
13843          * the variable again.
13844          */
13845         orig_next_vreg = cfg->next_vreg;
13846         vreg_to_lvreg = (guint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
13847         lvregs = (guint32 *)mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
13848         lvregs_len = 0;
13849
13850         /* 
13851          * These arrays contain the first and last instructions accessing a given
13852          * variable.
13853          * Since we emit bblocks in the same order we process them here, and we
13854          * don't split live ranges, these will precisely describe the live range of
13855          * the variable, i.e. the instruction range where a valid value can be found
13856          * in the variables location.
13857          * The live range is computed using the liveness info computed by the liveness pass.
13858          * We can't use vmv->range, since that is an abstract live range, and we need
13859          * one which is instruction precise.
13860          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
13861          */
13862         /* FIXME: Only do this if debugging info is requested */
13863         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
13864         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
13865         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
13866         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
13867         
13868         /* Add spill loads/stores */
13869         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13870                 MonoInst *ins;
13871
13872                 if (cfg->verbose_level > 2)
13873                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
13874
13875                 /* Clear vreg_to_lvreg array */
13876                 for (i = 0; i < lvregs_len; i++)
13877                         vreg_to_lvreg [lvregs [i]] = 0;
13878                 lvregs_len = 0;
13879
13880                 cfg->cbb = bb;
13881                 MONO_BB_FOR_EACH_INS (bb, ins) {
13882                         const char *spec = INS_INFO (ins->opcode);
13883                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
13884                         gboolean store, no_lvreg;
13885                         int sregs [MONO_MAX_SRC_REGS];
13886
13887                         if (G_UNLIKELY (cfg->verbose_level > 2))
13888                                 mono_print_ins (ins);
13889
13890                         if (ins->opcode == OP_NOP)
13891                                 continue;
13892
13893                         /* 
13894                          * We handle LDADDR here as well, since it can only be decomposed
13895                          * when variable addresses are known.
13896                          */
13897                         if (ins->opcode == OP_LDADDR) {
13898                                 MonoInst *var = (MonoInst *)ins->inst_p0;
13899
13900                                 if (var->opcode == OP_VTARG_ADDR) {
13901                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
13902                                         MonoInst *vtaddr = var->inst_left;
13903                                         if (vtaddr->opcode == OP_REGVAR) {
13904                                                 ins->opcode = OP_MOVE;
13905                                                 ins->sreg1 = vtaddr->dreg;
13906                                         }
13907                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
13908                                                 ins->opcode = OP_LOAD_MEMBASE;
13909                                                 ins->inst_basereg = vtaddr->inst_basereg;
13910                                                 ins->inst_offset = vtaddr->inst_offset;
13911                                         } else
13912                                                 NOT_IMPLEMENTED;
13913                                 } else if (cfg->gsharedvt && cfg->gsharedvt_vreg_to_idx [var->dreg] < 0) {
13914                                         /* gsharedvt arg passed by ref */
13915                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
13916
13917                                         ins->opcode = OP_LOAD_MEMBASE;
13918                                         ins->inst_basereg = var->inst_basereg;
13919                                         ins->inst_offset = var->inst_offset;
13920                                 } else if (cfg->gsharedvt && cfg->gsharedvt_vreg_to_idx [var->dreg]) {
13921                                         MonoInst *load, *load2, *load3;
13922                                         int idx = cfg->gsharedvt_vreg_to_idx [var->dreg] - 1;
13923                                         int reg1, reg2, reg3;
13924                                         MonoInst *info_var = cfg->gsharedvt_info_var;
13925                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
13926
13927                                         /*
13928                                          * gsharedvt local.
13929                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
13930                                          */
13931
13932                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
13933
13934                                         g_assert (info_var);
13935                                         g_assert (locals_var);
13936
13937                                         /* Mark the instruction used to compute the locals var as used */
13938                                         cfg->gsharedvt_locals_var_ins = NULL;
13939
13940                                         /* Load the offset */
13941                                         if (info_var->opcode == OP_REGOFFSET) {
13942                                                 reg1 = alloc_ireg (cfg);
13943                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
13944                                         } else if (info_var->opcode == OP_REGVAR) {
13945                                                 load = NULL;
13946                                                 reg1 = info_var->dreg;
13947                                         } else {
13948                                                 g_assert_not_reached ();
13949                                         }
13950                                         reg2 = alloc_ireg (cfg);
13951                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
13952                                         /* Load the locals area address */
13953                                         reg3 = alloc_ireg (cfg);
13954                                         if (locals_var->opcode == OP_REGOFFSET) {
13955                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
13956                                         } else if (locals_var->opcode == OP_REGVAR) {
13957                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
13958                                         } else {
13959                                                 g_assert_not_reached ();
13960                                         }
13961                                         /* Compute the address */
13962                                         ins->opcode = OP_PADD;
13963                                         ins->sreg1 = reg3;
13964                                         ins->sreg2 = reg2;
13965
13966                                         mono_bblock_insert_before_ins (bb, ins, load3);
13967                                         mono_bblock_insert_before_ins (bb, load3, load2);
13968                                         if (load)
13969                                                 mono_bblock_insert_before_ins (bb, load2, load);
13970                                 } else {
13971                                         g_assert (var->opcode == OP_REGOFFSET);
13972
13973                                         ins->opcode = OP_ADD_IMM;
13974                                         ins->sreg1 = var->inst_basereg;
13975                                         ins->inst_imm = var->inst_offset;
13976                                 }
13977
13978                                 *need_local_opts = TRUE;
13979                                 spec = INS_INFO (ins->opcode);
13980                         }
13981
13982                         if (ins->opcode < MONO_CEE_LAST) {
13983                                 mono_print_ins (ins);
13984                                 g_assert_not_reached ();
13985                         }
13986
13987                         /*
13988                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
13989                          * src register.
13990                          * FIXME:
13991                          */
13992                         if (MONO_IS_STORE_MEMBASE (ins)) {
13993                                 tmp_reg = ins->dreg;
13994                                 ins->dreg = ins->sreg2;
13995                                 ins->sreg2 = tmp_reg;
13996                                 store = TRUE;
13997
13998                                 spec2 [MONO_INST_DEST] = ' ';
13999                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14000                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14001                                 spec2 [MONO_INST_SRC3] = ' ';
14002                                 spec = spec2;
14003                         } else if (MONO_IS_STORE_MEMINDEX (ins))
14004                                 g_assert_not_reached ();
14005                         else
14006                                 store = FALSE;
14007                         no_lvreg = FALSE;
14008
14009                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
14010                                 printf ("\t %.3s %d", spec, ins->dreg);
14011                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
14012                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
14013                                         printf (" %d", sregs [srcindex]);
14014                                 printf ("\n");
14015                         }
14016
14017                         /***************/
14018                         /*    DREG     */
14019                         /***************/
14020                         regtype = spec [MONO_INST_DEST];
14021                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
14022                         prev_dreg = -1;
14023
14024                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
14025                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
14026                                 MonoInst *store_ins;
14027                                 int store_opcode;
14028                                 MonoInst *def_ins = ins;
14029                                 int dreg = ins->dreg; /* The original vreg */
14030
14031                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
14032
14033                                 if (var->opcode == OP_REGVAR) {
14034                                         ins->dreg = var->dreg;
14035                                 } 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)) {
14036                                         /* 
14037                                          * Instead of emitting a load+store, use a _membase opcode.
14038                                          */
14039                                         g_assert (var->opcode == OP_REGOFFSET);
14040                                         if (ins->opcode == OP_MOVE) {
14041                                                 NULLIFY_INS (ins);
14042                                                 def_ins = NULL;
14043                                         } else {
14044                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
14045                                                 ins->inst_basereg = var->inst_basereg;
14046                                                 ins->inst_offset = var->inst_offset;
14047                                                 ins->dreg = -1;
14048                                         }
14049                                         spec = INS_INFO (ins->opcode);
14050                                 } else {
14051                                         guint32 lvreg;
14052
14053                                         g_assert (var->opcode == OP_REGOFFSET);
14054
14055                                         prev_dreg = ins->dreg;
14056
14057                                         /* Invalidate any previous lvreg for this vreg */
14058                                         vreg_to_lvreg [ins->dreg] = 0;
14059
14060                                         lvreg = 0;
14061
14062                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
14063                                                 regtype = 'l';
14064                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
14065                                         }
14066
14067                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
14068
14069 #if SIZEOF_REGISTER != 8
14070                                         if (regtype == 'l') {
14071                                                 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));
14072                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14073                                                 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));
14074                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14075                                                 def_ins = store_ins;
14076                                         }
14077                                         else
14078 #endif
14079                                         {
14080                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
14081
14082                                                 /* Try to fuse the store into the instruction itself */
14083                                                 /* FIXME: Add more instructions */
14084                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
14085                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
14086                                                         ins->inst_imm = ins->inst_c0;
14087                                                         ins->inst_destbasereg = var->inst_basereg;
14088                                                         ins->inst_offset = var->inst_offset;
14089                                                         spec = INS_INFO (ins->opcode);
14090                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE) || (ins->opcode == OP_RMOVE))) {
14091                                                         ins->opcode = store_opcode;
14092                                                         ins->inst_destbasereg = var->inst_basereg;
14093                                                         ins->inst_offset = var->inst_offset;
14094
14095                                                         no_lvreg = TRUE;
14096
14097                                                         tmp_reg = ins->dreg;
14098                                                         ins->dreg = ins->sreg2;
14099                                                         ins->sreg2 = tmp_reg;
14100                                                         store = TRUE;
14101
14102                                                         spec2 [MONO_INST_DEST] = ' ';
14103                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14104                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14105                                                         spec2 [MONO_INST_SRC3] = ' ';
14106                                                         spec = spec2;
14107                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
14108                                                         // FIXME: The backends expect the base reg to be in inst_basereg
14109                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
14110                                                         ins->dreg = -1;
14111                                                         ins->inst_basereg = var->inst_basereg;
14112                                                         ins->inst_offset = var->inst_offset;
14113                                                         spec = INS_INFO (ins->opcode);
14114                                                 } else {
14115                                                         /* printf ("INS: "); mono_print_ins (ins); */
14116                                                         /* Create a store instruction */
14117                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
14118
14119                                                         /* Insert it after the instruction */
14120                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
14121
14122                                                         def_ins = store_ins;
14123
14124                                                         /* 
14125                                                          * We can't assign ins->dreg to var->dreg here, since the
14126                                                          * sregs could use it. So set a flag, and do it after
14127                                                          * the sregs.
14128                                                          */
14129                                                         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)))
14130                                                                 dest_has_lvreg = TRUE;
14131                                                 }
14132                                         }
14133                                 }
14134
14135                                 if (def_ins && !live_range_start [dreg]) {
14136                                         live_range_start [dreg] = def_ins;
14137                                         live_range_start_bb [dreg] = bb;
14138                                 }
14139
14140                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
14141                                         MonoInst *tmp;
14142
14143                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
14144                                         tmp->inst_c1 = dreg;
14145                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
14146                                 }
14147                         }
14148
14149                         /************/
14150                         /*  SREGS   */
14151                         /************/
14152                         num_sregs = mono_inst_get_src_registers (ins, sregs);
14153                         for (srcindex = 0; srcindex < 3; ++srcindex) {
14154                                 regtype = spec [MONO_INST_SRC1 + srcindex];
14155                                 sreg = sregs [srcindex];
14156
14157                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
14158                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
14159                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
14160                                         MonoInst *use_ins = ins;
14161                                         MonoInst *load_ins;
14162                                         guint32 load_opcode;
14163
14164                                         if (var->opcode == OP_REGVAR) {
14165                                                 sregs [srcindex] = var->dreg;
14166                                                 //mono_inst_set_src_registers (ins, sregs);
14167                                                 live_range_end [sreg] = use_ins;
14168                                                 live_range_end_bb [sreg] = bb;
14169
14170                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14171                                                         MonoInst *tmp;
14172
14173                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14174                                                         /* var->dreg is a hreg */
14175                                                         tmp->inst_c1 = sreg;
14176                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
14177                                                 }
14178
14179                                                 continue;
14180                                         }
14181
14182                                         g_assert (var->opcode == OP_REGOFFSET);
14183                                                 
14184                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
14185
14186                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
14187
14188                                         if (vreg_to_lvreg [sreg]) {
14189                                                 g_assert (vreg_to_lvreg [sreg] != -1);
14190
14191                                                 /* The variable is already loaded to an lvreg */
14192                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14193                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
14194                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
14195                                                 //mono_inst_set_src_registers (ins, sregs);
14196                                                 continue;
14197                                         }
14198
14199                                         /* Try to fuse the load into the instruction */
14200                                         if ((srcindex == 0) && (op_to_op_src1_membase (cfg, load_opcode, ins->opcode) != -1)) {
14201                                                 ins->opcode = op_to_op_src1_membase (cfg, load_opcode, ins->opcode);
14202                                                 sregs [0] = var->inst_basereg;
14203                                                 //mono_inst_set_src_registers (ins, sregs);
14204                                                 ins->inst_offset = var->inst_offset;
14205                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (cfg, load_opcode, ins->opcode) != -1)) {
14206                                                 ins->opcode = op_to_op_src2_membase (cfg, load_opcode, ins->opcode);
14207                                                 sregs [1] = var->inst_basereg;
14208                                                 //mono_inst_set_src_registers (ins, sregs);
14209                                                 ins->inst_offset = var->inst_offset;
14210                                         } else {
14211                                                 if (MONO_IS_REAL_MOVE (ins)) {
14212                                                         ins->opcode = OP_NOP;
14213                                                         sreg = ins->dreg;
14214                                                 } else {
14215                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
14216
14217                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
14218
14219                                                         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) {
14220                                                                 if (var->dreg == prev_dreg) {
14221                                                                         /*
14222                                                                          * sreg refers to the value loaded by the load
14223                                                                          * emitted below, but we need to use ins->dreg
14224                                                                          * since it refers to the store emitted earlier.
14225                                                                          */
14226                                                                         sreg = ins->dreg;
14227                                                                 }
14228                                                                 g_assert (sreg != -1);
14229                                                                 vreg_to_lvreg [var->dreg] = sreg;
14230                                                                 g_assert (lvregs_len < 1024);
14231                                                                 lvregs [lvregs_len ++] = var->dreg;
14232                                                         }
14233                                                 }
14234
14235                                                 sregs [srcindex] = sreg;
14236                                                 //mono_inst_set_src_registers (ins, sregs);
14237
14238 #if SIZEOF_REGISTER != 8
14239                                                 if (regtype == 'l') {
14240                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_MS (sreg), var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
14241                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14242                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_LS (sreg), var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
14243                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14244                                                         use_ins = load_ins;
14245                                                 }
14246                                                 else
14247 #endif
14248                                                 {
14249 #if SIZEOF_REGISTER == 4
14250                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
14251 #endif
14252                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
14253                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14254                                                         use_ins = load_ins;
14255                                                 }
14256                                         }
14257
14258                                         if (var->dreg < orig_next_vreg) {
14259                                                 live_range_end [var->dreg] = use_ins;
14260                                                 live_range_end_bb [var->dreg] = bb;
14261                                         }
14262
14263                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14264                                                 MonoInst *tmp;
14265
14266                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14267                                                 tmp->inst_c1 = var->dreg;
14268                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
14269                                         }
14270                                 }
14271                         }
14272                         mono_inst_set_src_registers (ins, sregs);
14273
14274                         if (dest_has_lvreg) {
14275                                 g_assert (ins->dreg != -1);
14276                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
14277                                 g_assert (lvregs_len < 1024);
14278                                 lvregs [lvregs_len ++] = prev_dreg;
14279                                 dest_has_lvreg = FALSE;
14280                         }
14281
14282                         if (store) {
14283                                 tmp_reg = ins->dreg;
14284                                 ins->dreg = ins->sreg2;
14285                                 ins->sreg2 = tmp_reg;
14286                         }
14287
14288                         if (MONO_IS_CALL (ins)) {
14289                                 /* Clear vreg_to_lvreg array */
14290                                 for (i = 0; i < lvregs_len; i++)
14291                                         vreg_to_lvreg [lvregs [i]] = 0;
14292                                 lvregs_len = 0;
14293                         } else if (ins->opcode == OP_NOP) {
14294                                 ins->dreg = -1;
14295                                 MONO_INST_NULLIFY_SREGS (ins);
14296                         }
14297
14298                         if (cfg->verbose_level > 2)
14299                                 mono_print_ins_index (1, ins);
14300                 }
14301
14302                 /* Extend the live range based on the liveness info */
14303                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
14304                         for (i = 0; i < cfg->num_varinfo; i ++) {
14305                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
14306
14307                                 if (vreg_is_volatile (cfg, vi->vreg))
14308                                         /* The liveness info is incomplete */
14309                                         continue;
14310
14311                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
14312                                         /* Live from at least the first ins of this bb */
14313                                         live_range_start [vi->vreg] = bb->code;
14314                                         live_range_start_bb [vi->vreg] = bb;
14315                                 }
14316
14317                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
14318                                         /* Live at least until the last ins of this bb */
14319                                         live_range_end [vi->vreg] = bb->last_ins;
14320                                         live_range_end_bb [vi->vreg] = bb;
14321                                 }
14322                         }
14323                 }
14324         }
14325         
14326         /*
14327          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
14328          * by storing the current native offset into MonoMethodVar->live_range_start/end.
14329          */
14330         if (cfg->backend->have_liverange_ops && cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
14331                 for (i = 0; i < cfg->num_varinfo; ++i) {
14332                         int vreg = MONO_VARINFO (cfg, i)->vreg;
14333                         MonoInst *ins;
14334
14335                         if (live_range_start [vreg]) {
14336                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
14337                                 ins->inst_c0 = i;
14338                                 ins->inst_c1 = vreg;
14339                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
14340                         }
14341                         if (live_range_end [vreg]) {
14342                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
14343                                 ins->inst_c0 = i;
14344                                 ins->inst_c1 = vreg;
14345                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
14346                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
14347                                 else
14348                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
14349                         }
14350                 }
14351         }
14352
14353         if (cfg->gsharedvt_locals_var_ins) {
14354                 /* Nullify if unused */
14355                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
14356                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
14357         }
14358
14359         g_free (live_range_start);
14360         g_free (live_range_end);
14361         g_free (live_range_start_bb);
14362         g_free (live_range_end_bb);
14363 }
14364
14365
14366 /**
14367  * FIXME:
14368  * - use 'iadd' instead of 'int_add'
14369  * - handling ovf opcodes: decompose in method_to_ir.
14370  * - unify iregs/fregs
14371  *   -> partly done, the missing parts are:
14372  *   - a more complete unification would involve unifying the hregs as well, so
14373  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
14374  *     would no longer map to the machine hregs, so the code generators would need to
14375  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
14376  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
14377  *     fp/non-fp branches speeds it up by about 15%.
14378  * - use sext/zext opcodes instead of shifts
14379  * - add OP_ICALL
14380  * - get rid of TEMPLOADs if possible and use vregs instead
14381  * - clean up usage of OP_P/OP_ opcodes
14382  * - cleanup usage of DUMMY_USE
14383  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
14384  *   stack
14385  * - set the stack type and allocate a dreg in the EMIT_NEW macros
14386  * - get rid of all the <foo>2 stuff when the new JIT is ready.
14387  * - make sure handle_stack_args () is called before the branch is emitted
14388  * - when the new IR is done, get rid of all unused stuff
14389  * - COMPARE/BEQ as separate instructions or unify them ?
14390  *   - keeping them separate allows specialized compare instructions like
14391  *     compare_imm, compare_membase
14392  *   - most back ends unify fp compare+branch, fp compare+ceq
14393  * - integrate mono_save_args into inline_method
14394  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
14395  * - handle long shift opts on 32 bit platforms somehow: they require 
14396  *   3 sregs (2 for arg1 and 1 for arg2)
14397  * - make byref a 'normal' type.
14398  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
14399  *   variable if needed.
14400  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
14401  *   like inline_method.
14402  * - remove inlining restrictions
14403  * - fix LNEG and enable cfold of INEG
14404  * - generalize x86 optimizations like ldelema as a peephole optimization
14405  * - add store_mem_imm for amd64
14406  * - optimize the loading of the interruption flag in the managed->native wrappers
14407  * - avoid special handling of OP_NOP in passes
14408  * - move code inserting instructions into one function/macro.
14409  * - try a coalescing phase after liveness analysis
14410  * - add float -> vreg conversion + local optimizations on !x86
14411  * - figure out how to handle decomposed branches during optimizations, ie.
14412  *   compare+branch, op_jump_table+op_br etc.
14413  * - promote RuntimeXHandles to vregs
14414  * - vtype cleanups:
14415  *   - add a NEW_VARLOADA_VREG macro
14416  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
14417  *   accessing vtype fields.
14418  * - get rid of I8CONST on 64 bit platforms
14419  * - dealing with the increase in code size due to branches created during opcode
14420  *   decomposition:
14421  *   - use extended basic blocks
14422  *     - all parts of the JIT
14423  *     - handle_global_vregs () && local regalloc
14424  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
14425  * - sources of increase in code size:
14426  *   - vtypes
14427  *   - long compares
14428  *   - isinst and castclass
14429  *   - lvregs not allocated to global registers even if used multiple times
14430  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
14431  *   meaningful.
14432  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
14433  * - add all micro optimizations from the old JIT
14434  * - put tree optimizations into the deadce pass
14435  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
14436  *   specific function.
14437  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
14438  *   fcompare + branchCC.
14439  * - create a helper function for allocating a stack slot, taking into account 
14440  *   MONO_CFG_HAS_SPILLUP.
14441  * - merge r68207.
14442  * - merge the ia64 switch changes.
14443  * - optimize mono_regstate2_alloc_int/float.
14444  * - fix the pessimistic handling of variables accessed in exception handler blocks.
14445  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
14446  *   parts of the tree could be separated by other instructions, killing the tree
14447  *   arguments, or stores killing loads etc. Also, should we fold loads into other
14448  *   instructions if the result of the load is used multiple times ?
14449  * - make the REM_IMM optimization in mini-x86.c arch-independent.
14450  * - LAST MERGE: 108395.
14451  * - when returning vtypes in registers, generate IR and append it to the end of the
14452  *   last bb instead of doing it in the epilog.
14453  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
14454  */
14455
14456 /*
14457
14458 NOTES
14459 -----
14460
14461 - When to decompose opcodes:
14462   - earlier: this makes some optimizations hard to implement, since the low level IR
14463   no longer contains the neccessary information. But it is easier to do.
14464   - later: harder to implement, enables more optimizations.
14465 - Branches inside bblocks:
14466   - created when decomposing complex opcodes. 
14467     - branches to another bblock: harmless, but not tracked by the branch 
14468       optimizations, so need to branch to a label at the start of the bblock.
14469     - branches to inside the same bblock: very problematic, trips up the local
14470       reg allocator. Can be fixed by spitting the current bblock, but that is a
14471       complex operation, since some local vregs can become global vregs etc.
14472 - Local/global vregs:
14473   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
14474     local register allocator.
14475   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
14476     structure, created by mono_create_var (). Assigned to hregs or the stack by
14477     the global register allocator.
14478 - When to do optimizations like alu->alu_imm:
14479   - earlier -> saves work later on since the IR will be smaller/simpler
14480   - later -> can work on more instructions
14481 - Handling of valuetypes:
14482   - When a vtype is pushed on the stack, a new temporary is created, an 
14483     instruction computing its address (LDADDR) is emitted and pushed on
14484     the stack. Need to optimize cases when the vtype is used immediately as in
14485     argument passing, stloc etc.
14486 - Instead of the to_end stuff in the old JIT, simply call the function handling
14487   the values on the stack before emitting the last instruction of the bb.
14488 */
14489
14490 #else /* !DISABLE_JIT */
14491
14492 MONO_EMPTY_SOURCE_FILE (method_to_ir);
14493
14494 #endif /* !DISABLE_JIT */