f32d494b186bfebdbaedbbe61a35cbb813364610
[mono.git] / mono / mini / method-to-ir.c
1 /*
2  * method-to-ir.c: Convert CIL to the JIT internal representation
3  *
4  * Author:
5  *   Paolo Molaro (lupus@ximian.com)
6  *   Dietmar Maurer (dietmar@ximian.com)
7  *
8  * (C) 2002 Ximian, Inc.
9  * Copyright 2003-2010 Novell, Inc (http://www.novell.com)
10  * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
11  */
12
13 #include <config.h>
14
15 #ifndef DISABLE_JIT
16
17 #include <signal.h>
18
19 #ifdef HAVE_UNISTD_H
20 #include <unistd.h>
21 #endif
22
23 #include <math.h>
24 #include <string.h>
25 #include <ctype.h>
26
27 #ifdef HAVE_SYS_TIME_H
28 #include <sys/time.h>
29 #endif
30
31 #ifdef HAVE_ALLOCA_H
32 #include <alloca.h>
33 #endif
34
35 #include <mono/utils/memcheck.h>
36 #include "mini.h"
37 #include <mono/metadata/abi-details.h>
38 #include <mono/metadata/assembly.h>
39 #include <mono/metadata/attrdefs.h>
40 #include <mono/metadata/loader.h>
41 #include <mono/metadata/tabledefs.h>
42 #include <mono/metadata/class.h>
43 #include <mono/metadata/object.h>
44 #include <mono/metadata/exception.h>
45 #include <mono/metadata/opcodes.h>
46 #include <mono/metadata/mono-endian.h>
47 #include <mono/metadata/tokentype.h>
48 #include <mono/metadata/tabledefs.h>
49 #include <mono/metadata/marshal.h>
50 #include <mono/metadata/debug-helpers.h>
51 #include <mono/metadata/mono-debug.h>
52 #include <mono/metadata/mono-debug-debugger.h>
53 #include <mono/metadata/gc-internals.h>
54 #include <mono/metadata/security-manager.h>
55 #include <mono/metadata/threads-types.h>
56 #include <mono/metadata/security-core-clr.h>
57 #include <mono/metadata/profiler-private.h>
58 #include <mono/metadata/profiler.h>
59 #include <mono/metadata/monitor.h>
60 #include <mono/metadata/debug-mono-symfile.h>
61 #include <mono/utils/mono-compiler.h>
62 #include <mono/utils/mono-memory-model.h>
63 #include <mono/utils/mono-error-internals.h>
64 #include <mono/metadata/mono-basic-block.h>
65 #include <mono/metadata/reflection-internals.h>
66
67 #include "trace.h"
68
69 #include "ir-emit.h"
70
71 #include "jit-icalls.h"
72 #include "jit.h"
73 #include "debugger-agent.h"
74 #include "seq-points.h"
75 #include "aot-compiler.h"
76 #include "mini-llvm.h"
77
78 #define BRANCH_COST 10
79 #define INLINE_LENGTH_LIMIT 20
80
81 /* These have 'cfg' as an implicit argument */
82 #define INLINE_FAILURE(msg) do {                                                                        \
83         if ((cfg->method != cfg->current_method) && (cfg->current_method->wrapper_type == MONO_WRAPPER_NONE)) { \
84                 inline_failure (cfg, msg);                                                                              \
85                 goto exception_exit;                                                                                    \
86         } \
87         } while (0)
88 #define CHECK_CFG_EXCEPTION do {\
89                 if (cfg->exception_type != MONO_EXCEPTION_NONE) \
90                         goto exception_exit;                                            \
91         } while (0)
92 #define METHOD_ACCESS_FAILURE(method, cmethod) do {                     \
93                 method_access_failure ((cfg), (method), (cmethod));                     \
94                 goto exception_exit;                                                                            \
95         } while (0)
96 #define FIELD_ACCESS_FAILURE(method, field) do {                                        \
97                 field_access_failure ((cfg), (method), (field));                        \
98                 goto exception_exit;    \
99         } while (0)
100 #define GENERIC_SHARING_FAILURE(opcode) do {            \
101                 if (cfg->gshared) {                                                                     \
102                         gshared_failure (cfg, opcode, __FILE__, __LINE__);      \
103                         goto exception_exit;    \
104                 }                       \
105         } while (0)
106 #define GSHAREDVT_FAILURE(opcode) do {          \
107         if (cfg->gsharedvt) {                                                                                           \
108                 gsharedvt_failure (cfg, opcode, __FILE__, __LINE__);                    \
109                 goto exception_exit;                                                                                    \
110         }                                                                                                                                       \
111         } while (0)
112 #define OUT_OF_MEMORY_FAILURE do {      \
113                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);                \
114                 mono_error_set_out_of_memory (&cfg->error, "");                                 \
115                 goto exception_exit;    \
116         } while (0)
117 #define DISABLE_AOT(cfg) do { \
118                 if ((cfg)->verbose_level >= 2)                                            \
119                         printf ("AOT disabled: %s:%d\n", __FILE__, __LINE__);   \
120                 (cfg)->disable_aot = TRUE;                                                        \
121         } while (0)
122 #define LOAD_ERROR do { \
123                 break_on_unverified ();                                                         \
124                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD); \
125                 goto exception_exit;                                                                    \
126         } while (0)
127
128 #define TYPE_LOAD_ERROR(klass) do { \
129                 cfg->exception_ptr = klass; \
130                 LOAD_ERROR;                                     \
131         } while (0)
132
133 #define CHECK_CFG_ERROR do {\
134                 if (!mono_error_ok (&cfg->error)) { \
135                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);        \
136                         goto mono_error_exit; \
137                 } \
138         } while (0)
139
140 /* Determine whenever 'ins' represents a load of the 'this' argument */
141 #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && ((ins)->opcode == OP_MOVE) && ((ins)->sreg1 == cfg->args [0]->dreg))
142
143 static int ldind_to_load_membase (int opcode);
144 static int stind_to_store_membase (int opcode);
145
146 int mono_op_to_op_imm (int opcode);
147 int mono_op_to_op_imm_noemul (int opcode);
148
149 MONO_API MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
150
151 static int inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
152                                                   guchar *ip, guint real_offset, gboolean inline_always);
153 static MonoInst*
154 emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used, MonoInst **sp);
155
156 /* helper methods signatures */
157 static MonoMethodSignature *helper_sig_domain_get;
158 static MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline;
159 static MonoMethodSignature *helper_sig_llvmonly_imt_thunk;
160
161
162 /* type loading helpers */
163 static GENERATE_GET_CLASS_WITH_CACHE (runtime_helpers, System.Runtime.CompilerServices, RuntimeHelpers)
164 static GENERATE_TRY_GET_CLASS_WITH_CACHE (debuggable_attribute, System.Diagnostics, DebuggableAttribute)
165
166 /*
167  * Instruction metadata
168  */
169 #ifdef MINI_OP
170 #undef MINI_OP
171 #endif
172 #ifdef MINI_OP3
173 #undef MINI_OP3
174 #endif
175 #define MINI_OP(a,b,dest,src1,src2) dest, src1, src2, ' ',
176 #define MINI_OP3(a,b,dest,src1,src2,src3) dest, src1, src2, src3,
177 #define NONE ' '
178 #define IREG 'i'
179 #define FREG 'f'
180 #define VREG 'v'
181 #define XREG 'x'
182 #if SIZEOF_REGISTER == 8 && SIZEOF_REGISTER == SIZEOF_VOID_P
183 #define LREG IREG
184 #else
185 #define LREG 'l'
186 #endif
187 /* keep in sync with the enum in mini.h */
188 const char
189 ins_info[] = {
190 #include "mini-ops.h"
191 };
192 #undef MINI_OP
193 #undef MINI_OP3
194
195 #define MINI_OP(a,b,dest,src1,src2) ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0)),
196 #define MINI_OP3(a,b,dest,src1,src2,src3) ((src3) != NONE ? 3 : ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0))),
197 /* 
198  * This should contain the index of the last sreg + 1. This is not the same
199  * as the number of sregs for opcodes like IA64_CMP_EQ_IMM.
200  */
201 const gint8 ins_sreg_counts[] = {
202 #include "mini-ops.h"
203 };
204 #undef MINI_OP
205 #undef MINI_OP3
206
207 #define MONO_INIT_VARINFO(vi,id) do { \
208         (vi)->range.first_use.pos.bid = 0xffff; \
209         (vi)->reg = -1; \
210         (vi)->idx = (id); \
211 } while (0)
212
213 guint32
214 mono_alloc_ireg (MonoCompile *cfg)
215 {
216         return alloc_ireg (cfg);
217 }
218
219 guint32
220 mono_alloc_lreg (MonoCompile *cfg)
221 {
222         return alloc_lreg (cfg);
223 }
224
225 guint32
226 mono_alloc_freg (MonoCompile *cfg)
227 {
228         return alloc_freg (cfg);
229 }
230
231 guint32
232 mono_alloc_preg (MonoCompile *cfg)
233 {
234         return alloc_preg (cfg);
235 }
236
237 guint32
238 mono_alloc_dreg (MonoCompile *cfg, MonoStackType stack_type)
239 {
240         return alloc_dreg (cfg, stack_type);
241 }
242
243 /*
244  * mono_alloc_ireg_ref:
245  *
246  *   Allocate an IREG, and mark it as holding a GC ref.
247  */
248 guint32
249 mono_alloc_ireg_ref (MonoCompile *cfg)
250 {
251         return alloc_ireg_ref (cfg);
252 }
253
254 /*
255  * mono_alloc_ireg_mp:
256  *
257  *   Allocate an IREG, and mark it as holding a managed pointer.
258  */
259 guint32
260 mono_alloc_ireg_mp (MonoCompile *cfg)
261 {
262         return alloc_ireg_mp (cfg);
263 }
264
265 /*
266  * mono_alloc_ireg_copy:
267  *
268  *   Allocate an IREG with the same GC type as VREG.
269  */
270 guint32
271 mono_alloc_ireg_copy (MonoCompile *cfg, guint32 vreg)
272 {
273         if (vreg_is_ref (cfg, vreg))
274                 return alloc_ireg_ref (cfg);
275         else if (vreg_is_mp (cfg, vreg))
276                 return alloc_ireg_mp (cfg);
277         else
278                 return alloc_ireg (cfg);
279 }
280
281 guint
282 mono_type_to_regmove (MonoCompile *cfg, MonoType *type)
283 {
284         if (type->byref)
285                 return OP_MOVE;
286
287         type = mini_get_underlying_type (type);
288 handle_enum:
289         switch (type->type) {
290         case MONO_TYPE_I1:
291         case MONO_TYPE_U1:
292                 return OP_MOVE;
293         case MONO_TYPE_I2:
294         case MONO_TYPE_U2:
295                 return OP_MOVE;
296         case MONO_TYPE_I4:
297         case MONO_TYPE_U4:
298                 return OP_MOVE;
299         case MONO_TYPE_I:
300         case MONO_TYPE_U:
301         case MONO_TYPE_PTR:
302         case MONO_TYPE_FNPTR:
303                 return OP_MOVE;
304         case MONO_TYPE_CLASS:
305         case MONO_TYPE_STRING:
306         case MONO_TYPE_OBJECT:
307         case MONO_TYPE_SZARRAY:
308         case MONO_TYPE_ARRAY:    
309                 return OP_MOVE;
310         case MONO_TYPE_I8:
311         case MONO_TYPE_U8:
312 #if SIZEOF_REGISTER == 8
313                 return OP_MOVE;
314 #else
315                 return OP_LMOVE;
316 #endif
317         case MONO_TYPE_R4:
318                 return cfg->r4fp ? OP_RMOVE : OP_FMOVE;
319         case MONO_TYPE_R8:
320                 return OP_FMOVE;
321         case MONO_TYPE_VALUETYPE:
322                 if (type->data.klass->enumtype) {
323                         type = mono_class_enum_basetype (type->data.klass);
324                         goto handle_enum;
325                 }
326                 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
327                         return OP_XMOVE;
328                 return OP_VMOVE;
329         case MONO_TYPE_TYPEDBYREF:
330                 return OP_VMOVE;
331         case MONO_TYPE_GENERICINST:
332                 type = &type->data.generic_class->container_class->byval_arg;
333                 goto handle_enum;
334         case MONO_TYPE_VAR:
335         case MONO_TYPE_MVAR:
336                 g_assert (cfg->gshared);
337                 if (mini_type_var_is_vt (type))
338                         return OP_VMOVE;
339                 else
340                         return mono_type_to_regmove (cfg, mini_get_underlying_type (type));
341         default:
342                 g_error ("unknown type 0x%02x in type_to_regstore", type->type);
343         }
344         return -1;
345 }
346
347 void
348 mono_print_bb (MonoBasicBlock *bb, const char *msg)
349 {
350         int i;
351         MonoInst *tree;
352
353         printf ("\n%s %d: [IN: ", msg, bb->block_num);
354         for (i = 0; i < bb->in_count; ++i)
355                 printf (" BB%d(%d)", bb->in_bb [i]->block_num, bb->in_bb [i]->dfn);
356         printf (", OUT: ");
357         for (i = 0; i < bb->out_count; ++i)
358                 printf (" BB%d(%d)", bb->out_bb [i]->block_num, bb->out_bb [i]->dfn);
359         printf (" ]\n");
360         for (tree = bb->code; tree; tree = tree->next)
361                 mono_print_ins_index (-1, tree);
362 }
363
364 void
365 mono_create_helper_signatures (void)
366 {
367         helper_sig_domain_get = mono_create_icall_signature ("ptr");
368         helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
369         helper_sig_llvmonly_imt_thunk = mono_create_icall_signature ("ptr ptr ptr");
370 }
371
372 static MONO_NEVER_INLINE void
373 break_on_unverified (void)
374 {
375         if (mini_get_debug_options ()->break_on_unverified)
376                 G_BREAKPOINT ();
377 }
378
379 static MONO_NEVER_INLINE void
380 method_access_failure (MonoCompile *cfg, MonoMethod *method, MonoMethod *cil_method)
381 {
382         char *method_fname = mono_method_full_name (method, TRUE);
383         char *cil_method_fname = mono_method_full_name (cil_method, TRUE);
384         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
385         mono_error_set_generic_error (&cfg->error, "System", "MethodAccessException", "Method `%s' is inaccessible from method `%s'\n", cil_method_fname, method_fname);
386         g_free (method_fname);
387         g_free (cil_method_fname);
388 }
389
390 static MONO_NEVER_INLINE void
391 field_access_failure (MonoCompile *cfg, MonoMethod *method, MonoClassField *field)
392 {
393         char *method_fname = mono_method_full_name (method, TRUE);
394         char *field_fname = mono_field_full_name (field);
395         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
396         mono_error_set_generic_error (&cfg->error, "System", "FieldAccessException", "Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname);
397         g_free (method_fname);
398         g_free (field_fname);
399 }
400
401 static MONO_NEVER_INLINE void
402 inline_failure (MonoCompile *cfg, const char *msg)
403 {
404         if (cfg->verbose_level >= 2)
405                 printf ("inline failed: %s\n", msg);
406         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INLINE_FAILED);
407 }
408
409 static MONO_NEVER_INLINE void
410 gshared_failure (MonoCompile *cfg, int opcode, const char *file, int line)
411 {
412         if (cfg->verbose_level > 2)                                                                                     \
413                 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);
414         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
415 }
416
417 static MONO_NEVER_INLINE void
418 gsharedvt_failure (MonoCompile *cfg, int opcode, const char *file, int line)
419 {
420         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);
421         if (cfg->verbose_level >= 2)
422                 printf ("%s\n", cfg->exception_message);
423         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
424 }
425
426 /*
427  * When using gsharedvt, some instatiations might be verifiable, and some might be not. i.e. 
428  * foo<T> (int i) { ldarg.0; box T; }
429  */
430 #define UNVERIFIED do { \
431         if (cfg->gsharedvt) { \
432                 if (cfg->verbose_level > 2)                                                                     \
433                         printf ("gsharedvt method failed to verify, falling back to instantiation.\n"); \
434                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \
435                 goto exception_exit;                                                                                    \
436         }                                                                                                                                       \
437         break_on_unverified ();                                                                                         \
438         goto unverified;                                                                                                        \
439 } while (0)
440
441 #define GET_BBLOCK(cfg,tblock,ip) do {  \
442                 (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
443                 if (!(tblock)) {        \
444                         if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
445             NEW_BBLOCK (cfg, (tblock)); \
446                         (tblock)->cil_code = (ip);      \
447                         ADD_BBLOCK (cfg, (tblock));     \
448                 } \
449         } while (0)
450
451 #if defined(TARGET_X86) || defined(TARGET_AMD64)
452 #define EMIT_NEW_X86_LEA(cfg,dest,sr1,sr2,shift,imm) do { \
453                 MONO_INST_NEW (cfg, dest, OP_X86_LEA); \
454                 (dest)->dreg = alloc_ireg_mp ((cfg)); \
455                 (dest)->sreg1 = (sr1); \
456                 (dest)->sreg2 = (sr2); \
457                 (dest)->inst_imm = (imm); \
458                 (dest)->backend.shift_amount = (shift); \
459                 MONO_ADD_INS ((cfg)->cbb, (dest)); \
460         } while (0)
461 #endif
462
463 /* Emit conversions so both operands of a binary opcode are of the same type */
464 static void
465 add_widen_op (MonoCompile *cfg, MonoInst *ins, MonoInst **arg1_ref, MonoInst **arg2_ref)
466 {
467         MonoInst *arg1 = *arg1_ref;
468         MonoInst *arg2 = *arg2_ref;
469
470         if (cfg->r4fp &&
471                 ((arg1->type == STACK_R4 && arg2->type == STACK_R8) ||
472                  (arg1->type == STACK_R8 && arg2->type == STACK_R4))) {
473                 MonoInst *conv;
474
475                 /* Mixing r4/r8 is allowed by the spec */
476                 if (arg1->type == STACK_R4) {
477                         int dreg = alloc_freg (cfg);
478
479                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg1->dreg);
480                         conv->type = STACK_R8;
481                         ins->sreg1 = dreg;
482                         *arg1_ref = conv;
483                 }
484                 if (arg2->type == STACK_R4) {
485                         int dreg = alloc_freg (cfg);
486
487                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg2->dreg);
488                         conv->type = STACK_R8;
489                         ins->sreg2 = dreg;
490                         *arg2_ref = conv;
491                 }
492         }
493
494 #if SIZEOF_REGISTER == 8
495         /* FIXME: Need to add many more cases */
496         if ((arg1)->type == STACK_PTR && (arg2)->type == STACK_I4) {
497                 MonoInst *widen;
498
499                 int dr = alloc_preg (cfg);
500                 EMIT_NEW_UNALU (cfg, widen, OP_SEXT_I4, dr, (arg2)->dreg);
501                 (ins)->sreg2 = widen->dreg;
502         }
503 #endif
504 }
505
506 #define ADD_BINOP(op) do {      \
507                 MONO_INST_NEW (cfg, ins, (op)); \
508                 sp -= 2;        \
509                 ins->sreg1 = sp [0]->dreg;      \
510                 ins->sreg2 = sp [1]->dreg;      \
511                 type_from_op (cfg, ins, sp [0], sp [1]);        \
512                 CHECK_TYPE (ins);       \
513                 /* Have to insert a widening op */               \
514         add_widen_op (cfg, ins, &sp [0], &sp [1]);               \
515         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type); \
516         MONO_ADD_INS ((cfg)->cbb, (ins)); \
517         *sp++ = mono_decompose_opcode ((cfg), (ins));   \
518         } while (0)
519
520 #define ADD_UNOP(op) do {       \
521                 MONO_INST_NEW (cfg, ins, (op)); \
522                 sp--;   \
523                 ins->sreg1 = sp [0]->dreg;      \
524                 type_from_op (cfg, ins, sp [0], NULL);  \
525                 CHECK_TYPE (ins);       \
526         (ins)->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type); \
527         MONO_ADD_INS ((cfg)->cbb, (ins)); \
528                 *sp++ = mono_decompose_opcode (cfg, ins);       \
529         } while (0)
530
531 #define ADD_BINCOND(next_block) do {    \
532                 MonoInst *cmp;  \
533                 sp -= 2; \
534                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
535                 cmp->sreg1 = sp [0]->dreg;      \
536                 cmp->sreg2 = sp [1]->dreg;      \
537                 type_from_op (cfg, cmp, sp [0], sp [1]);        \
538                 CHECK_TYPE (cmp);       \
539                 add_widen_op (cfg, cmp, &sp [0], &sp [1]);                                              \
540                 type_from_op (cfg, ins, sp [0], sp [1]);                                                        \
541                 ins->inst_many_bb = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);   \
542                 GET_BBLOCK (cfg, tblock, target);               \
543                 link_bblock (cfg, cfg->cbb, tblock);    \
544                 ins->inst_true_bb = tblock;     \
545                 if ((next_block)) {     \
546                         link_bblock (cfg, cfg->cbb, (next_block));      \
547                         ins->inst_false_bb = (next_block);      \
548                         start_new_bblock = 1;   \
549                 } else {        \
550                         GET_BBLOCK (cfg, tblock, ip);           \
551                         link_bblock (cfg, cfg->cbb, tblock);    \
552                         ins->inst_false_bb = tblock;    \
553                         start_new_bblock = 2;   \
554                 }       \
555                 if (sp != stack_start) {                                                                        \
556                     handle_stack_args (cfg, stack_start, sp - stack_start); \
557                         CHECK_UNVERIFIABLE (cfg); \
558                 } \
559         MONO_ADD_INS (cfg->cbb, cmp); \
560                 MONO_ADD_INS (cfg->cbb, ins);   \
561         } while (0)
562
563 /* *
564  * link_bblock: Links two basic blocks
565  *
566  * links two basic blocks in the control flow graph, the 'from'
567  * argument is the starting block and the 'to' argument is the block
568  * the control flow ends to after 'from'.
569  */
570 static void
571 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
572 {
573         MonoBasicBlock **newa;
574         int i, found;
575
576 #if 0
577         if (from->cil_code) {
578                 if (to->cil_code)
579                         printf ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
580                 else
581                         printf ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
582         } else {
583                 if (to->cil_code)
584                         printf ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
585                 else
586                         printf ("edge from entry to exit\n");
587         }
588 #endif
589
590         found = FALSE;
591         for (i = 0; i < from->out_count; ++i) {
592                 if (to == from->out_bb [i]) {
593                         found = TRUE;
594                         break;
595                 }
596         }
597         if (!found) {
598                 newa = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
599                 for (i = 0; i < from->out_count; ++i) {
600                         newa [i] = from->out_bb [i];
601                 }
602                 newa [i] = to;
603                 from->out_count++;
604                 from->out_bb = newa;
605         }
606
607         found = FALSE;
608         for (i = 0; i < to->in_count; ++i) {
609                 if (from == to->in_bb [i]) {
610                         found = TRUE;
611                         break;
612                 }
613         }
614         if (!found) {
615                 newa = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
616                 for (i = 0; i < to->in_count; ++i) {
617                         newa [i] = to->in_bb [i];
618                 }
619                 newa [i] = from;
620                 to->in_count++;
621                 to->in_bb = newa;
622         }
623 }
624
625 void
626 mono_link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
627 {
628         link_bblock (cfg, from, to);
629 }
630
631 /**
632  * mono_find_block_region:
633  *
634  *   We mark each basic block with a region ID. We use that to avoid BB
635  *   optimizations when blocks are in different regions.
636  *
637  * Returns:
638  *   A region token that encodes where this region is, and information
639  *   about the clause owner for this block.
640  *
641  *   The region encodes the try/catch/filter clause that owns this block
642  *   as well as the type.  -1 is a special value that represents a block
643  *   that is in none of try/catch/filter.
644  */
645 static int
646 mono_find_block_region (MonoCompile *cfg, int offset)
647 {
648         MonoMethodHeader *header = cfg->header;
649         MonoExceptionClause *clause;
650         int i;
651
652         for (i = 0; i < header->num_clauses; ++i) {
653                 clause = &header->clauses [i];
654                 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
655                     (offset < (clause->handler_offset)))
656                         return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
657                            
658                 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
659                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
660                                 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
661                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
662                                 return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
663                         else
664                                 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
665                 }
666         }
667         for (i = 0; i < header->num_clauses; ++i) {
668                 clause = &header->clauses [i];
669
670                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
671                         return ((i + 1) << 8) | clause->flags;
672         }
673
674         return -1;
675 }
676
677 static GList*
678 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
679 {
680         MonoMethodHeader *header = cfg->header;
681         MonoExceptionClause *clause;
682         int i;
683         GList *res = NULL;
684
685         for (i = 0; i < header->num_clauses; ++i) {
686                 clause = &header->clauses [i];
687                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
688                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
689                         if (clause->flags == type)
690                                 res = g_list_append (res, clause);
691                 }
692         }
693         return res;
694 }
695
696 static void
697 mono_create_spvar_for_region (MonoCompile *cfg, int region)
698 {
699         MonoInst *var;
700
701         var = (MonoInst *)g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
702         if (var)
703                 return;
704
705         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
706         /* prevent it from being register allocated */
707         var->flags |= MONO_INST_VOLATILE;
708
709         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
710 }
711
712 MonoInst *
713 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
714 {
715         return (MonoInst *)g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
716 }
717
718 static MonoInst*
719 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
720 {
721         MonoInst *var;
722
723         var = (MonoInst *)g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
724         if (var)
725                 return var;
726
727         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
728         /* prevent it from being register allocated */
729         var->flags |= MONO_INST_VOLATILE;
730
731         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
732
733         return var;
734 }
735
736 /*
737  * Returns the type used in the eval stack when @type is loaded.
738  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
739  */
740 void
741 type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
742 {
743         MonoClass *klass;
744
745         type = mini_get_underlying_type (type);
746         inst->klass = klass = mono_class_from_mono_type (type);
747         if (type->byref) {
748                 inst->type = STACK_MP;
749                 return;
750         }
751
752 handle_enum:
753         switch (type->type) {
754         case MONO_TYPE_VOID:
755                 inst->type = STACK_INV;
756                 return;
757         case MONO_TYPE_I1:
758         case MONO_TYPE_U1:
759         case MONO_TYPE_I2:
760         case MONO_TYPE_U2:
761         case MONO_TYPE_I4:
762         case MONO_TYPE_U4:
763                 inst->type = STACK_I4;
764                 return;
765         case MONO_TYPE_I:
766         case MONO_TYPE_U:
767         case MONO_TYPE_PTR:
768         case MONO_TYPE_FNPTR:
769                 inst->type = STACK_PTR;
770                 return;
771         case MONO_TYPE_CLASS:
772         case MONO_TYPE_STRING:
773         case MONO_TYPE_OBJECT:
774         case MONO_TYPE_SZARRAY:
775         case MONO_TYPE_ARRAY:    
776                 inst->type = STACK_OBJ;
777                 return;
778         case MONO_TYPE_I8:
779         case MONO_TYPE_U8:
780                 inst->type = STACK_I8;
781                 return;
782         case MONO_TYPE_R4:
783                 inst->type = cfg->r4_stack_type;
784                 break;
785         case MONO_TYPE_R8:
786                 inst->type = STACK_R8;
787                 return;
788         case MONO_TYPE_VALUETYPE:
789                 if (type->data.klass->enumtype) {
790                         type = mono_class_enum_basetype (type->data.klass);
791                         goto handle_enum;
792                 } else {
793                         inst->klass = klass;
794                         inst->type = STACK_VTYPE;
795                         return;
796                 }
797         case MONO_TYPE_TYPEDBYREF:
798                 inst->klass = mono_defaults.typed_reference_class;
799                 inst->type = STACK_VTYPE;
800                 return;
801         case MONO_TYPE_GENERICINST:
802                 type = &type->data.generic_class->container_class->byval_arg;
803                 goto handle_enum;
804         case MONO_TYPE_VAR:
805         case MONO_TYPE_MVAR:
806                 g_assert (cfg->gshared);
807                 if (mini_is_gsharedvt_type (type)) {
808                         g_assert (cfg->gsharedvt);
809                         inst->type = STACK_VTYPE;
810                 } else {
811                         type_to_eval_stack_type (cfg, mini_get_underlying_type (type), inst);
812                 }
813                 return;
814         default:
815                 g_error ("unknown type 0x%02x in eval stack type", type->type);
816         }
817 }
818
819 /*
820  * The following tables are used to quickly validate the IL code in type_from_op ().
821  */
822 static const char
823 bin_num_table [STACK_MAX] [STACK_MAX] = {
824         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
825         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
826         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
827         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
828         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV, STACK_R8},
829         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
830         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
831         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
832         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4}
833 };
834
835 static const char 
836 neg_table [] = {
837         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4
838 };
839
840 /* reduce the size of this table */
841 static const char
842 bin_int_table [STACK_MAX] [STACK_MAX] = {
843         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
844         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
845         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
846         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
847         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
848         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
849         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
850         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
851 };
852
853 static const char
854 bin_comp_table [STACK_MAX] [STACK_MAX] = {
855 /*      Inv i  L  p  F  &  O  vt r4 */
856         {0},
857         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
858         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
859         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
860         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* F, R8 */
861         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
862         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
863         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
864         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* r, r4 */
865 };
866
867 /* reduce the size of this table */
868 static const char
869 shift_table [STACK_MAX] [STACK_MAX] = {
870         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
871         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
872         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
873         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
874         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
875         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
876         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
877         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
878 };
879
880 /*
881  * Tables to map from the non-specific opcode to the matching
882  * type-specific opcode.
883  */
884 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
885 static const guint16
886 binops_op_map [STACK_MAX] = {
887         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
888 };
889
890 /* handles from CEE_NEG to CEE_CONV_U8 */
891 static const guint16
892 unops_op_map [STACK_MAX] = {
893         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
894 };
895
896 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
897 static const guint16
898 ovfops_op_map [STACK_MAX] = {
899         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
900 };
901
902 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
903 static const guint16
904 ovf2ops_op_map [STACK_MAX] = {
905         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
906 };
907
908 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
909 static const guint16
910 ovf3ops_op_map [STACK_MAX] = {
911         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
912 };
913
914 /* handles from CEE_BEQ to CEE_BLT_UN */
915 static const guint16
916 beqops_op_map [STACK_MAX] = {
917         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
918 };
919
920 /* handles from CEE_CEQ to CEE_CLT_UN */
921 static const guint16
922 ceqops_op_map [STACK_MAX] = {
923         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
924 };
925
926 /*
927  * Sets ins->type (the type on the eval stack) according to the
928  * type of the opcode and the arguments to it.
929  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
930  *
931  * FIXME: this function sets ins->type unconditionally in some cases, but
932  * it should set it to invalid for some types (a conv.x on an object)
933  */
934 static void
935 type_from_op (MonoCompile *cfg, MonoInst *ins, MonoInst *src1, MonoInst *src2)
936 {
937         switch (ins->opcode) {
938         /* binops */
939         case CEE_ADD:
940         case CEE_SUB:
941         case CEE_MUL:
942         case CEE_DIV:
943         case CEE_REM:
944                 /* FIXME: check unverifiable args for STACK_MP */
945                 ins->type = bin_num_table [src1->type] [src2->type];
946                 ins->opcode += binops_op_map [ins->type];
947                 break;
948         case CEE_DIV_UN:
949         case CEE_REM_UN:
950         case CEE_AND:
951         case CEE_OR:
952         case CEE_XOR:
953                 ins->type = bin_int_table [src1->type] [src2->type];
954                 ins->opcode += binops_op_map [ins->type];
955                 break;
956         case CEE_SHL:
957         case CEE_SHR:
958         case CEE_SHR_UN:
959                 ins->type = shift_table [src1->type] [src2->type];
960                 ins->opcode += binops_op_map [ins->type];
961                 break;
962         case OP_COMPARE:
963         case OP_LCOMPARE:
964         case OP_ICOMPARE:
965                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
966                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
967                         ins->opcode = OP_LCOMPARE;
968                 else if (src1->type == STACK_R4)
969                         ins->opcode = OP_RCOMPARE;
970                 else if (src1->type == STACK_R8)
971                         ins->opcode = OP_FCOMPARE;
972                 else
973                         ins->opcode = OP_ICOMPARE;
974                 break;
975         case OP_ICOMPARE_IMM:
976                 ins->type = bin_comp_table [src1->type] [src1->type] ? STACK_I4 : STACK_INV;
977                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
978                         ins->opcode = OP_LCOMPARE_IMM;          
979                 break;
980         case CEE_BEQ:
981         case CEE_BGE:
982         case CEE_BGT:
983         case CEE_BLE:
984         case CEE_BLT:
985         case CEE_BNE_UN:
986         case CEE_BGE_UN:
987         case CEE_BGT_UN:
988         case CEE_BLE_UN:
989         case CEE_BLT_UN:
990                 ins->opcode += beqops_op_map [src1->type];
991                 break;
992         case OP_CEQ:
993                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
994                 ins->opcode += ceqops_op_map [src1->type];
995                 break;
996         case OP_CGT:
997         case OP_CGT_UN:
998         case OP_CLT:
999         case OP_CLT_UN:
1000                 ins->type = (bin_comp_table [src1->type] [src2->type] & 1) ? STACK_I4: STACK_INV;
1001                 ins->opcode += ceqops_op_map [src1->type];
1002                 break;
1003         /* unops */
1004         case CEE_NEG:
1005                 ins->type = neg_table [src1->type];
1006                 ins->opcode += unops_op_map [ins->type];
1007                 break;
1008         case CEE_NOT:
1009                 if (src1->type >= STACK_I4 && src1->type <= STACK_PTR)
1010                         ins->type = src1->type;
1011                 else
1012                         ins->type = STACK_INV;
1013                 ins->opcode += unops_op_map [ins->type];
1014                 break;
1015         case CEE_CONV_I1:
1016         case CEE_CONV_I2:
1017         case CEE_CONV_I4:
1018         case CEE_CONV_U4:
1019                 ins->type = STACK_I4;
1020                 ins->opcode += unops_op_map [src1->type];
1021                 break;
1022         case CEE_CONV_R_UN:
1023                 ins->type = STACK_R8;
1024                 switch (src1->type) {
1025                 case STACK_I4:
1026                 case STACK_PTR:
1027                         ins->opcode = OP_ICONV_TO_R_UN;
1028                         break;
1029                 case STACK_I8:
1030                         ins->opcode = OP_LCONV_TO_R_UN; 
1031                         break;
1032                 }
1033                 break;
1034         case CEE_CONV_OVF_I1:
1035         case CEE_CONV_OVF_U1:
1036         case CEE_CONV_OVF_I2:
1037         case CEE_CONV_OVF_U2:
1038         case CEE_CONV_OVF_I4:
1039         case CEE_CONV_OVF_U4:
1040                 ins->type = STACK_I4;
1041                 ins->opcode += ovf3ops_op_map [src1->type];
1042                 break;
1043         case CEE_CONV_OVF_I_UN:
1044         case CEE_CONV_OVF_U_UN:
1045                 ins->type = STACK_PTR;
1046                 ins->opcode += ovf2ops_op_map [src1->type];
1047                 break;
1048         case CEE_CONV_OVF_I1_UN:
1049         case CEE_CONV_OVF_I2_UN:
1050         case CEE_CONV_OVF_I4_UN:
1051         case CEE_CONV_OVF_U1_UN:
1052         case CEE_CONV_OVF_U2_UN:
1053         case CEE_CONV_OVF_U4_UN:
1054                 ins->type = STACK_I4;
1055                 ins->opcode += ovf2ops_op_map [src1->type];
1056                 break;
1057         case CEE_CONV_U:
1058                 ins->type = STACK_PTR;
1059                 switch (src1->type) {
1060                 case STACK_I4:
1061                         ins->opcode = OP_ICONV_TO_U;
1062                         break;
1063                 case STACK_PTR:
1064                 case STACK_MP:
1065 #if SIZEOF_VOID_P == 8
1066                         ins->opcode = OP_LCONV_TO_U;
1067 #else
1068                         ins->opcode = OP_MOVE;
1069 #endif
1070                         break;
1071                 case STACK_I8:
1072                         ins->opcode = OP_LCONV_TO_U;
1073                         break;
1074                 case STACK_R8:
1075                         ins->opcode = OP_FCONV_TO_U;
1076                         break;
1077                 }
1078                 break;
1079         case CEE_CONV_I8:
1080         case CEE_CONV_U8:
1081                 ins->type = STACK_I8;
1082                 ins->opcode += unops_op_map [src1->type];
1083                 break;
1084         case CEE_CONV_OVF_I8:
1085         case CEE_CONV_OVF_U8:
1086                 ins->type = STACK_I8;
1087                 ins->opcode += ovf3ops_op_map [src1->type];
1088                 break;
1089         case CEE_CONV_OVF_U8_UN:
1090         case CEE_CONV_OVF_I8_UN:
1091                 ins->type = STACK_I8;
1092                 ins->opcode += ovf2ops_op_map [src1->type];
1093                 break;
1094         case CEE_CONV_R4:
1095                 ins->type = cfg->r4_stack_type;
1096                 ins->opcode += unops_op_map [src1->type];
1097                 break;
1098         case CEE_CONV_R8:
1099                 ins->type = STACK_R8;
1100                 ins->opcode += unops_op_map [src1->type];
1101                 break;
1102         case OP_CKFINITE:
1103                 ins->type = STACK_R8;           
1104                 break;
1105         case CEE_CONV_U2:
1106         case CEE_CONV_U1:
1107                 ins->type = STACK_I4;
1108                 ins->opcode += ovfops_op_map [src1->type];
1109                 break;
1110         case CEE_CONV_I:
1111         case CEE_CONV_OVF_I:
1112         case CEE_CONV_OVF_U:
1113                 ins->type = STACK_PTR;
1114                 ins->opcode += ovfops_op_map [src1->type];
1115                 break;
1116         case CEE_ADD_OVF:
1117         case CEE_ADD_OVF_UN:
1118         case CEE_MUL_OVF:
1119         case CEE_MUL_OVF_UN:
1120         case CEE_SUB_OVF:
1121         case CEE_SUB_OVF_UN:
1122                 ins->type = bin_num_table [src1->type] [src2->type];
1123                 ins->opcode += ovfops_op_map [src1->type];
1124                 if (ins->type == STACK_R8)
1125                         ins->type = STACK_INV;
1126                 break;
1127         case OP_LOAD_MEMBASE:
1128                 ins->type = STACK_PTR;
1129                 break;
1130         case OP_LOADI1_MEMBASE:
1131         case OP_LOADU1_MEMBASE:
1132         case OP_LOADI2_MEMBASE:
1133         case OP_LOADU2_MEMBASE:
1134         case OP_LOADI4_MEMBASE:
1135         case OP_LOADU4_MEMBASE:
1136                 ins->type = STACK_PTR;
1137                 break;
1138         case OP_LOADI8_MEMBASE:
1139                 ins->type = STACK_I8;
1140                 break;
1141         case OP_LOADR4_MEMBASE:
1142                 ins->type = cfg->r4_stack_type;
1143                 break;
1144         case OP_LOADR8_MEMBASE:
1145                 ins->type = STACK_R8;
1146                 break;
1147         default:
1148                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1149                 break;
1150         }
1151
1152         if (ins->type == STACK_MP)
1153                 ins->klass = mono_defaults.object_class;
1154 }
1155
1156 static const char 
1157 ldind_type [] = {
1158         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
1159 };
1160
1161 #if 0
1162
1163 static const char
1164 param_table [STACK_MAX] [STACK_MAX] = {
1165         {0},
1166 };
1167
1168 static int
1169 check_values_to_signature (MonoInst *args, MonoType *this_ins, MonoMethodSignature *sig)
1170 {
1171         int i;
1172
1173         if (sig->hasthis) {
1174                 switch (args->type) {
1175                 case STACK_I4:
1176                 case STACK_I8:
1177                 case STACK_R8:
1178                 case STACK_VTYPE:
1179                 case STACK_INV:
1180                         return 0;
1181                 }
1182                 args++;
1183         }
1184         for (i = 0; i < sig->param_count; ++i) {
1185                 switch (args [i].type) {
1186                 case STACK_INV:
1187                         return 0;
1188                 case STACK_MP:
1189                         if (!sig->params [i]->byref)
1190                                 return 0;
1191                         continue;
1192                 case STACK_OBJ:
1193                         if (sig->params [i]->byref)
1194                                 return 0;
1195                         switch (sig->params [i]->type) {
1196                         case MONO_TYPE_CLASS:
1197                         case MONO_TYPE_STRING:
1198                         case MONO_TYPE_OBJECT:
1199                         case MONO_TYPE_SZARRAY:
1200                         case MONO_TYPE_ARRAY:
1201                                 break;
1202                         default:
1203                                 return 0;
1204                         }
1205                         continue;
1206                 case STACK_R8:
1207                         if (sig->params [i]->byref)
1208                                 return 0;
1209                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1210                                 return 0;
1211                         continue;
1212                 case STACK_PTR:
1213                 case STACK_I4:
1214                 case STACK_I8:
1215                 case STACK_VTYPE:
1216                         break;
1217                 }
1218                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1219                         return 0;*/
1220         }
1221         return 1;
1222 }
1223 #endif
1224
1225 /*
1226  * When we need a pointer to the current domain many times in a method, we
1227  * call mono_domain_get() once and we store the result in a local variable.
1228  * This function returns the variable that represents the MonoDomain*.
1229  */
1230 inline static MonoInst *
1231 mono_get_domainvar (MonoCompile *cfg)
1232 {
1233         if (!cfg->domainvar)
1234                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1235         return cfg->domainvar;
1236 }
1237
1238 /*
1239  * The got_var contains the address of the Global Offset Table when AOT 
1240  * compiling.
1241  */
1242 MonoInst *
1243 mono_get_got_var (MonoCompile *cfg)
1244 {
1245         if (!cfg->compile_aot || !cfg->backend->need_got_var)
1246                 return NULL;
1247         if (!cfg->got_var) {
1248                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1249         }
1250         return cfg->got_var;
1251 }
1252
1253 static MonoInst *
1254 mono_get_vtable_var (MonoCompile *cfg)
1255 {
1256         g_assert (cfg->gshared);
1257
1258         if (!cfg->rgctx_var) {
1259                 cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1260                 /* force the var to be stack allocated */
1261                 cfg->rgctx_var->flags |= MONO_INST_VOLATILE;
1262         }
1263
1264         return cfg->rgctx_var;
1265 }
1266
1267 static MonoType*
1268 type_from_stack_type (MonoInst *ins) {
1269         switch (ins->type) {
1270         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1271         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1272         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1273         case STACK_R4: return &mono_defaults.single_class->byval_arg;
1274         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1275         case STACK_MP:
1276                 return &ins->klass->this_arg;
1277         case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1278         case STACK_VTYPE: return &ins->klass->byval_arg;
1279         default:
1280                 g_error ("stack type %d to monotype not handled\n", ins->type);
1281         }
1282         return NULL;
1283 }
1284
1285 static G_GNUC_UNUSED int
1286 type_to_stack_type (MonoCompile *cfg, MonoType *t)
1287 {
1288         t = mono_type_get_underlying_type (t);
1289         switch (t->type) {
1290         case MONO_TYPE_I1:
1291         case MONO_TYPE_U1:
1292         case MONO_TYPE_I2:
1293         case MONO_TYPE_U2:
1294         case MONO_TYPE_I4:
1295         case MONO_TYPE_U4:
1296                 return STACK_I4;
1297         case MONO_TYPE_I:
1298         case MONO_TYPE_U:
1299         case MONO_TYPE_PTR:
1300         case MONO_TYPE_FNPTR:
1301                 return STACK_PTR;
1302         case MONO_TYPE_CLASS:
1303         case MONO_TYPE_STRING:
1304         case MONO_TYPE_OBJECT:
1305         case MONO_TYPE_SZARRAY:
1306         case MONO_TYPE_ARRAY:    
1307                 return STACK_OBJ;
1308         case MONO_TYPE_I8:
1309         case MONO_TYPE_U8:
1310                 return STACK_I8;
1311         case MONO_TYPE_R4:
1312                 return cfg->r4_stack_type;
1313         case MONO_TYPE_R8:
1314                 return STACK_R8;
1315         case MONO_TYPE_VALUETYPE:
1316         case MONO_TYPE_TYPEDBYREF:
1317                 return STACK_VTYPE;
1318         case MONO_TYPE_GENERICINST:
1319                 if (mono_type_generic_inst_is_valuetype (t))
1320                         return STACK_VTYPE;
1321                 else
1322                         return STACK_OBJ;
1323                 break;
1324         default:
1325                 g_assert_not_reached ();
1326         }
1327
1328         return -1;
1329 }
1330
1331 static MonoClass*
1332 array_access_to_klass (int opcode)
1333 {
1334         switch (opcode) {
1335         case CEE_LDELEM_U1:
1336                 return mono_defaults.byte_class;
1337         case CEE_LDELEM_U2:
1338                 return mono_defaults.uint16_class;
1339         case CEE_LDELEM_I:
1340         case CEE_STELEM_I:
1341                 return mono_defaults.int_class;
1342         case CEE_LDELEM_I1:
1343         case CEE_STELEM_I1:
1344                 return mono_defaults.sbyte_class;
1345         case CEE_LDELEM_I2:
1346         case CEE_STELEM_I2:
1347                 return mono_defaults.int16_class;
1348         case CEE_LDELEM_I4:
1349         case CEE_STELEM_I4:
1350                 return mono_defaults.int32_class;
1351         case CEE_LDELEM_U4:
1352                 return mono_defaults.uint32_class;
1353         case CEE_LDELEM_I8:
1354         case CEE_STELEM_I8:
1355                 return mono_defaults.int64_class;
1356         case CEE_LDELEM_R4:
1357         case CEE_STELEM_R4:
1358                 return mono_defaults.single_class;
1359         case CEE_LDELEM_R8:
1360         case CEE_STELEM_R8:
1361                 return mono_defaults.double_class;
1362         case CEE_LDELEM_REF:
1363         case CEE_STELEM_REF:
1364                 return mono_defaults.object_class;
1365         default:
1366                 g_assert_not_reached ();
1367         }
1368         return NULL;
1369 }
1370
1371 /*
1372  * We try to share variables when possible
1373  */
1374 static MonoInst *
1375 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1376 {
1377         MonoInst *res;
1378         int pos, vnum;
1379
1380         /* inlining can result in deeper stacks */ 
1381         if (slot >= cfg->header->max_stack)
1382                 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1383
1384         pos = ins->type - 1 + slot * STACK_MAX;
1385
1386         switch (ins->type) {
1387         case STACK_I4:
1388         case STACK_I8:
1389         case STACK_R8:
1390         case STACK_PTR:
1391         case STACK_MP:
1392         case STACK_OBJ:
1393                 if ((vnum = cfg->intvars [pos]))
1394                         return cfg->varinfo [vnum];
1395                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1396                 cfg->intvars [pos] = res->inst_c0;
1397                 break;
1398         default:
1399                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1400         }
1401         return res;
1402 }
1403
1404 static void
1405 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
1406 {
1407         /* 
1408          * Don't use this if a generic_context is set, since that means AOT can't
1409          * look up the method using just the image+token.
1410          * table == 0 means this is a reference made from a wrapper.
1411          */
1412         if (cfg->compile_aot && !cfg->generic_context && (mono_metadata_token_table (token) > 0)) {
1413                 MonoJumpInfoToken *jump_info_token = (MonoJumpInfoToken *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
1414                 jump_info_token->image = image;
1415                 jump_info_token->token = token;
1416                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
1417         }
1418 }
1419
1420 /*
1421  * This function is called to handle items that are left on the evaluation stack
1422  * at basic block boundaries. What happens is that we save the values to local variables
1423  * and we reload them later when first entering the target basic block (with the
1424  * handle_loaded_temps () function).
1425  * A single joint point will use the same variables (stored in the array bb->out_stack or
1426  * bb->in_stack, if the basic block is before or after the joint point).
1427  *
1428  * This function needs to be called _before_ emitting the last instruction of
1429  * the bb (i.e. before emitting a branch).
1430  * If the stack merge fails at a join point, cfg->unverifiable is set.
1431  */
1432 static void
1433 handle_stack_args (MonoCompile *cfg, MonoInst **sp, int count)
1434 {
1435         int i, bindex;
1436         MonoBasicBlock *bb = cfg->cbb;
1437         MonoBasicBlock *outb;
1438         MonoInst *inst, **locals;
1439         gboolean found;
1440
1441         if (!count)
1442                 return;
1443         if (cfg->verbose_level > 3)
1444                 printf ("%d item(s) on exit from B%d\n", count, bb->block_num);
1445         if (!bb->out_scount) {
1446                 bb->out_scount = count;
1447                 //printf ("bblock %d has out:", bb->block_num);
1448                 found = FALSE;
1449                 for (i = 0; i < bb->out_count; ++i) {
1450                         outb = bb->out_bb [i];
1451                         /* exception handlers are linked, but they should not be considered for stack args */
1452                         if (outb->flags & BB_EXCEPTION_HANDLER)
1453                                 continue;
1454                         //printf (" %d", outb->block_num);
1455                         if (outb->in_stack) {
1456                                 found = TRUE;
1457                                 bb->out_stack = outb->in_stack;
1458                                 break;
1459                         }
1460                 }
1461                 //printf ("\n");
1462                 if (!found) {
1463                         bb->out_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1464                         for (i = 0; i < count; ++i) {
1465                                 /* 
1466                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
1467                                  * stack slot and if they are of the same type.
1468                                  * This won't cause conflicts since if 'local' is used to 
1469                                  * store one of the values in the in_stack of a bblock, then
1470                                  * the same variable will be used for the same outgoing stack 
1471                                  * slot as well. 
1472                                  * This doesn't work when inlining methods, since the bblocks
1473                                  * in the inlined methods do not inherit their in_stack from
1474                                  * the bblock they are inlined to. See bug #58863 for an
1475                                  * example.
1476                                  */
1477                                 if (cfg->inlined_method)
1478                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1479                                 else
1480                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1481                         }
1482                 }
1483         }
1484
1485         for (i = 0; i < bb->out_count; ++i) {
1486                 outb = bb->out_bb [i];
1487                 /* exception handlers are linked, but they should not be considered for stack args */
1488                 if (outb->flags & BB_EXCEPTION_HANDLER)
1489                         continue;
1490                 if (outb->in_scount) {
1491                         if (outb->in_scount != bb->out_scount) {
1492                                 cfg->unverifiable = TRUE;
1493                                 return;
1494                         }
1495                         continue; /* check they are the same locals */
1496                 }
1497                 outb->in_scount = count;
1498                 outb->in_stack = bb->out_stack;
1499         }
1500
1501         locals = bb->out_stack;
1502         cfg->cbb = bb;
1503         for (i = 0; i < count; ++i) {
1504                 EMIT_NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1505                 inst->cil_code = sp [i]->cil_code;
1506                 sp [i] = locals [i];
1507                 if (cfg->verbose_level > 3)
1508                         printf ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
1509         }
1510
1511         /*
1512          * It is possible that the out bblocks already have in_stack assigned, and
1513          * the in_stacks differ. In this case, we will store to all the different 
1514          * in_stacks.
1515          */
1516
1517         found = TRUE;
1518         bindex = 0;
1519         while (found) {
1520                 /* Find a bblock which has a different in_stack */
1521                 found = FALSE;
1522                 while (bindex < bb->out_count) {
1523                         outb = bb->out_bb [bindex];
1524                         /* exception handlers are linked, but they should not be considered for stack args */
1525                         if (outb->flags & BB_EXCEPTION_HANDLER) {
1526                                 bindex++;
1527                                 continue;
1528                         }
1529                         if (outb->in_stack != locals) {
1530                                 for (i = 0; i < count; ++i) {
1531                                         EMIT_NEW_TEMPSTORE (cfg, inst, outb->in_stack [i]->inst_c0, sp [i]);
1532                                         inst->cil_code = sp [i]->cil_code;
1533                                         sp [i] = locals [i];
1534                                         if (cfg->verbose_level > 3)
1535                                                 printf ("storing %d to temp %d\n", i, (int)outb->in_stack [i]->inst_c0);
1536                                 }
1537                                 locals = outb->in_stack;
1538                                 found = TRUE;
1539                                 break;
1540                         }
1541                         bindex ++;
1542                 }
1543         }
1544 }
1545
1546 static MonoInst*
1547 emit_runtime_constant (MonoCompile *cfg, MonoJumpInfoType patch_type, gpointer data)
1548 {
1549         MonoInst *ins;
1550
1551         if (cfg->compile_aot) {
1552                 EMIT_NEW_AOTCONST (cfg, ins, patch_type, data);
1553         } else {
1554                 MonoJumpInfo ji;
1555                 gpointer target;
1556                 MonoError error;
1557
1558                 ji.type = patch_type;
1559                 ji.data.target = data;
1560                 target = mono_resolve_patch_target (NULL, cfg->domain, NULL, &ji, FALSE, &error);
1561                 mono_error_assert_ok (&error);
1562
1563                 EMIT_NEW_PCONST (cfg, ins, target);
1564         }
1565         return ins;
1566 }
1567
1568 static void
1569 mini_emit_interface_bitmap_check (MonoCompile *cfg, int intf_bit_reg, int base_reg, int offset, MonoClass *klass)
1570 {
1571         int ibitmap_reg = alloc_preg (cfg);
1572 #ifdef COMPRESSED_INTERFACE_BITMAP
1573         MonoInst *args [2];
1574         MonoInst *res, *ins;
1575         NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, ibitmap_reg, base_reg, offset);
1576         MONO_ADD_INS (cfg->cbb, ins);
1577         args [0] = ins;
1578         args [1] = emit_runtime_constant (cfg, MONO_PATCH_INFO_IID, klass);
1579         res = mono_emit_jit_icall (cfg, mono_class_interface_match, args);
1580         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, intf_bit_reg, res->dreg);
1581 #else
1582         int ibitmap_byte_reg = alloc_preg (cfg);
1583
1584         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, base_reg, offset);
1585
1586         if (cfg->compile_aot) {
1587                 int iid_reg = alloc_preg (cfg);
1588                 int shifted_iid_reg = alloc_preg (cfg);
1589                 int ibitmap_byte_address_reg = alloc_preg (cfg);
1590                 int masked_iid_reg = alloc_preg (cfg);
1591                 int iid_one_bit_reg = alloc_preg (cfg);
1592                 int iid_bit_reg = alloc_preg (cfg);
1593                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1594                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, shifted_iid_reg, iid_reg, 3);
1595                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ibitmap_byte_address_reg, ibitmap_reg, shifted_iid_reg);
1596                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, ibitmap_byte_reg, ibitmap_byte_address_reg, 0);
1597                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, masked_iid_reg, iid_reg, 7);
1598                 MONO_EMIT_NEW_ICONST (cfg, iid_one_bit_reg, 1);
1599                 MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg);
1600                 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg);
1601         } else {
1602                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
1603                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
1604         }
1605 #endif
1606 }
1607
1608 /* 
1609  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
1610  * stored in "klass_reg" implements the interface "klass".
1611  */
1612 static void
1613 mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass)
1614 {
1615         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, interface_bitmap), klass);
1616 }
1617
1618 /* 
1619  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoVTable
1620  * stored in "vtable_reg" implements the interface "klass".
1621  */
1622 static void
1623 mini_emit_load_intf_bit_reg_vtable (MonoCompile *cfg, int intf_bit_reg, int vtable_reg, MonoClass *klass)
1624 {
1625         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, interface_bitmap), klass);
1626 }
1627
1628 /* 
1629  * Emit code which checks whenever the interface id of @klass is smaller than
1630  * than the value given by max_iid_reg.
1631 */
1632 static void
1633 mini_emit_max_iid_check (MonoCompile *cfg, int max_iid_reg, MonoClass *klass,
1634                                                  MonoBasicBlock *false_target)
1635 {
1636         if (cfg->compile_aot) {
1637                 int iid_reg = alloc_preg (cfg);
1638                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1639                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, max_iid_reg, iid_reg);
1640         }
1641         else
1642                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, max_iid_reg, klass->interface_id);
1643         if (false_target)
1644                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1645         else
1646                 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1647 }
1648
1649 /* Same as above, but obtains max_iid from a vtable */
1650 static void
1651 mini_emit_max_iid_check_vtable (MonoCompile *cfg, int vtable_reg, MonoClass *klass,
1652                                                                  MonoBasicBlock *false_target)
1653 {
1654         int max_iid_reg = alloc_preg (cfg);
1655                 
1656         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, max_interface_id));
1657         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1658 }
1659
1660 /* Same as above, but obtains max_iid from a klass */
1661 static void
1662 mini_emit_max_iid_check_class (MonoCompile *cfg, int klass_reg, MonoClass *klass,
1663                                                                  MonoBasicBlock *false_target)
1664 {
1665         int max_iid_reg = alloc_preg (cfg);
1666
1667         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, max_interface_id));
1668         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1669 }
1670
1671 static void
1672 mini_emit_isninst_cast_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_ins, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1673 {
1674         int idepth_reg = alloc_preg (cfg);
1675         int stypes_reg = alloc_preg (cfg);
1676         int stype = alloc_preg (cfg);
1677
1678         mono_class_setup_supertypes (klass);
1679
1680         if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1681                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1682                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1683                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1684         }
1685         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1686         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1687         if (klass_ins) {
1688                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, klass_ins->dreg);
1689         } else if (cfg->compile_aot) {
1690                 int const_reg = alloc_preg (cfg);
1691                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1692                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, const_reg);
1693         } else {
1694                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, stype, klass);
1695         }
1696         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, true_target);
1697 }
1698
1699 static void
1700 mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1701 {
1702         mini_emit_isninst_cast_inst (cfg, klass_reg, klass, NULL, false_target, true_target);
1703 }
1704
1705 static void
1706 mini_emit_iface_cast (MonoCompile *cfg, int vtable_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1707 {
1708         int intf_reg = alloc_preg (cfg);
1709
1710         mini_emit_max_iid_check_vtable (cfg, vtable_reg, klass, false_target);
1711         mini_emit_load_intf_bit_reg_vtable (cfg, intf_reg, vtable_reg, klass);
1712         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_reg, 0);
1713         if (true_target)
1714                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1715         else
1716                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");               
1717 }
1718
1719 /*
1720  * Variant of the above that takes a register to the class, not the vtable.
1721  */
1722 static void
1723 mini_emit_iface_class_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1724 {
1725         int intf_bit_reg = alloc_preg (cfg);
1726
1727         mini_emit_max_iid_check_class (cfg, klass_reg, klass, false_target);
1728         mini_emit_load_intf_bit_reg_class (cfg, intf_bit_reg, klass_reg, klass);
1729         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_bit_reg, 0);
1730         if (true_target)
1731                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1732         else
1733                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
1734 }
1735
1736 static inline void
1737 mini_emit_class_check_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_inst)
1738 {
1739         if (klass_inst) {
1740                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_inst->dreg);
1741         } else {
1742                 MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
1743                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, ins->dreg);
1744         }
1745         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1746 }
1747
1748 static inline void
1749 mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
1750 {
1751         mini_emit_class_check_inst (cfg, klass_reg, klass, NULL);
1752 }
1753
1754 static inline void
1755 mini_emit_class_check_branch (MonoCompile *cfg, int klass_reg, MonoClass *klass, int branch_op, MonoBasicBlock *target)
1756 {
1757         if (cfg->compile_aot) {
1758                 int const_reg = alloc_preg (cfg);
1759                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1760                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1761         } else {
1762                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1763         }
1764         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, branch_op, target);
1765 }
1766
1767 static void
1768 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null);
1769         
1770 static void
1771 mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoInst *klass_inst, MonoBasicBlock *object_is_null)
1772 {
1773         if (klass->rank) {
1774                 int rank_reg = alloc_preg (cfg);
1775                 int eclass_reg = alloc_preg (cfg);
1776
1777                 g_assert (!klass_inst);
1778                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, rank));
1779                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
1780                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1781                 //              MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
1782                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
1783                 if (klass->cast_class == mono_defaults.object_class) {
1784                         int parent_reg = alloc_preg (cfg);
1785                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
1786                         mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, object_is_null);
1787                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1788                 } else if (klass->cast_class == mono_defaults.enum_class->parent) {
1789                         mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, object_is_null);
1790                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1791                 } else if (klass->cast_class == mono_defaults.enum_class) {
1792                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1793                 } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1794                         mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, NULL, NULL);
1795                 } else {
1796                         // Pass -1 as obj_reg to skip the check below for arrays of arrays
1797                         mini_emit_castclass (cfg, -1, eclass_reg, klass->cast_class, object_is_null);
1798                 }
1799
1800                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY) && (obj_reg != -1)) {
1801                         /* Check that the object is a vector too */
1802                         int bounds_reg = alloc_preg (cfg);
1803                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
1804                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
1805                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1806                 }
1807         } else {
1808                 int idepth_reg = alloc_preg (cfg);
1809                 int stypes_reg = alloc_preg (cfg);
1810                 int stype = alloc_preg (cfg);
1811
1812                 mono_class_setup_supertypes (klass);
1813
1814                 if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1815                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1816                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1817                         MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1818                 }
1819                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1820                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1821                 mini_emit_class_check_inst (cfg, stype, klass, klass_inst);
1822         }
1823 }
1824
1825 static void
1826 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null)
1827 {
1828         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, NULL, object_is_null);
1829 }
1830
1831 static void 
1832 mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
1833 {
1834         int val_reg;
1835
1836         g_assert (val == 0);
1837
1838         if (align == 0)
1839                 align = 4;
1840
1841         if ((size <= SIZEOF_REGISTER) && (size <= align)) {
1842                 switch (size) {
1843                 case 1:
1844                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, destreg, offset, val);
1845                         return;
1846                 case 2:
1847                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI2_MEMBASE_IMM, destreg, offset, val);
1848                         return;
1849                 case 4:
1850                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, destreg, offset, val);
1851                         return;
1852 #if SIZEOF_REGISTER == 8
1853                 case 8:
1854                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI8_MEMBASE_IMM, destreg, offset, val);
1855                         return;
1856 #endif
1857                 }
1858         }
1859
1860         val_reg = alloc_preg (cfg);
1861
1862         if (SIZEOF_REGISTER == 8)
1863                 MONO_EMIT_NEW_I8CONST (cfg, val_reg, val);
1864         else
1865                 MONO_EMIT_NEW_ICONST (cfg, val_reg, val);
1866
1867         if (align < 4) {
1868                 /* This could be optimized further if neccesary */
1869                 while (size >= 1) {
1870                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1871                         offset += 1;
1872                         size -= 1;
1873                 }
1874                 return;
1875         }       
1876
1877         if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
1878                 if (offset % 8) {
1879                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1880                         offset += 4;
1881                         size -= 4;
1882                 }
1883                 while (size >= 8) {
1884                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, offset, val_reg);
1885                         offset += 8;
1886                         size -= 8;
1887                 }
1888         }       
1889
1890         while (size >= 4) {
1891                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1892                 offset += 4;
1893                 size -= 4;
1894         }
1895         while (size >= 2) {
1896                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg);
1897                 offset += 2;
1898                 size -= 2;
1899         }
1900         while (size >= 1) {
1901                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1902                 offset += 1;
1903                 size -= 1;
1904         }
1905 }
1906
1907 void 
1908 mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
1909 {
1910         int cur_reg;
1911
1912         if (align == 0)
1913                 align = 4;
1914
1915         /*FIXME arbitrary hack to avoid unbound code expansion.*/
1916         g_assert (size < 10000);
1917
1918         if (align < 4) {
1919                 /* This could be optimized further if neccesary */
1920                 while (size >= 1) {
1921                         cur_reg = alloc_preg (cfg);
1922                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1923                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1924                         doffset += 1;
1925                         soffset += 1;
1926                         size -= 1;
1927                 }
1928         }
1929
1930         if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
1931                 while (size >= 8) {
1932                         cur_reg = alloc_preg (cfg);
1933                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI8_MEMBASE, cur_reg, srcreg, soffset);
1934                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, doffset, cur_reg);
1935                         doffset += 8;
1936                         soffset += 8;
1937                         size -= 8;
1938                 }
1939         }       
1940
1941         while (size >= 4) {
1942                 cur_reg = alloc_preg (cfg);
1943                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, cur_reg, srcreg, soffset);
1944                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, doffset, cur_reg);
1945                 doffset += 4;
1946                 soffset += 4;
1947                 size -= 4;
1948         }
1949         while (size >= 2) {
1950                 cur_reg = alloc_preg (cfg);
1951                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, cur_reg, srcreg, soffset);
1952                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, doffset, cur_reg);
1953                 doffset += 2;
1954                 soffset += 2;
1955                 size -= 2;
1956         }
1957         while (size >= 1) {
1958                 cur_reg = alloc_preg (cfg);
1959                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1960                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1961                 doffset += 1;
1962                 soffset += 1;
1963                 size -= 1;
1964         }
1965 }
1966
1967 static void
1968 emit_tls_set (MonoCompile *cfg, int sreg1, MonoTlsKey tls_key)
1969 {
1970         MonoInst *ins, *c;
1971
1972         if (cfg->compile_aot) {
1973                 EMIT_NEW_TLS_OFFSETCONST (cfg, c, tls_key);
1974                 MONO_INST_NEW (cfg, ins, OP_TLS_SET_REG);
1975                 ins->sreg1 = sreg1;
1976                 ins->sreg2 = c->dreg;
1977                 MONO_ADD_INS (cfg->cbb, ins);
1978         } else {
1979                 MONO_INST_NEW (cfg, ins, OP_TLS_SET);
1980                 ins->sreg1 = sreg1;
1981                 ins->inst_offset = mini_get_tls_offset (tls_key);
1982                 MONO_ADD_INS (cfg->cbb, ins);
1983         }
1984 }
1985
1986 /*
1987  * emit_push_lmf:
1988  *
1989  *   Emit IR to push the current LMF onto the LMF stack.
1990  */
1991 static void
1992 emit_push_lmf (MonoCompile *cfg)
1993 {
1994         /*
1995          * Emit IR to push the LMF:
1996          * lmf_addr = <lmf_addr from tls>
1997          * lmf->lmf_addr = lmf_addr
1998          * lmf->prev_lmf = *lmf_addr
1999          * *lmf_addr = lmf
2000          */
2001         int lmf_reg, prev_lmf_reg;
2002         MonoInst *ins, *lmf_ins;
2003
2004         if (!cfg->lmf_ir)
2005                 return;
2006
2007         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
2008                 /* Load current lmf */
2009                 lmf_ins = mono_get_lmf_intrinsic (cfg);
2010                 g_assert (lmf_ins);
2011                 MONO_ADD_INS (cfg->cbb, lmf_ins);
2012                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2013                 lmf_reg = ins->dreg;
2014                 /* Save previous_lmf */
2015                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), lmf_ins->dreg);
2016                 /* Set new LMF */
2017                 emit_tls_set (cfg, lmf_reg, TLS_KEY_LMF);
2018         } else {
2019                 /*
2020                  * Store lmf_addr in a variable, so it can be allocated to a global register.
2021                  */
2022                 if (!cfg->lmf_addr_var)
2023                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2024
2025 #ifdef HOST_WIN32
2026                 ins = mono_get_jit_tls_intrinsic (cfg);
2027                 if (ins) {
2028                         int jit_tls_dreg = ins->dreg;
2029
2030                         MONO_ADD_INS (cfg->cbb, ins);
2031                         lmf_reg = alloc_preg (cfg);
2032                         EMIT_NEW_BIALU_IMM (cfg, lmf_ins, OP_PADD_IMM, lmf_reg, jit_tls_dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2033                 } else {
2034                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2035                 }
2036 #else
2037                 lmf_ins = mono_get_lmf_addr_intrinsic (cfg);
2038                 if (lmf_ins) {
2039                         MONO_ADD_INS (cfg->cbb, lmf_ins);
2040                 } else {
2041 #ifdef TARGET_IOS
2042                         MonoInst *args [16], *jit_tls_ins, *ins;
2043
2044                         /* Inline mono_get_lmf_addr () */
2045                         /* jit_tls = pthread_getspecific (mono_jit_tls_id); lmf_addr = &jit_tls->lmf; */
2046
2047                         /* Load mono_jit_tls_id */
2048                         if (cfg->compile_aot)
2049                                 EMIT_NEW_AOTCONST (cfg, args [0], MONO_PATCH_INFO_JIT_TLS_ID, NULL);
2050                         else
2051                                 EMIT_NEW_ICONST (cfg, args [0], mono_jit_tls_id);
2052                         /* call pthread_getspecific () */
2053                         jit_tls_ins = mono_emit_jit_icall (cfg, pthread_getspecific, args);
2054                         /* lmf_addr = &jit_tls->lmf */
2055                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, cfg->lmf_addr_var->dreg, jit_tls_ins->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2056                         lmf_ins = ins;
2057 #else
2058                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2059 #endif
2060                 }
2061 #endif
2062                 lmf_ins->dreg = cfg->lmf_addr_var->dreg;
2063
2064                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2065                 lmf_reg = ins->dreg;
2066
2067                 prev_lmf_reg = alloc_preg (cfg);
2068                 /* Save previous_lmf */
2069                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, cfg->lmf_addr_var->dreg, 0);
2070                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), prev_lmf_reg);
2071                 /* Set new lmf */
2072                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, cfg->lmf_addr_var->dreg, 0, lmf_reg);
2073         }
2074 }
2075
2076 /*
2077  * emit_pop_lmf:
2078  *
2079  *   Emit IR to pop the current LMF from the LMF stack.
2080  */
2081 static void
2082 emit_pop_lmf (MonoCompile *cfg)
2083 {
2084         int lmf_reg, lmf_addr_reg, prev_lmf_reg;
2085         MonoInst *ins;
2086
2087         if (!cfg->lmf_ir)
2088                 return;
2089
2090         EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2091         lmf_reg = ins->dreg;
2092
2093         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
2094                 /* Load previous_lmf */
2095                 prev_lmf_reg = alloc_preg (cfg);
2096                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2097                 /* Set new LMF */
2098                 emit_tls_set (cfg, prev_lmf_reg, TLS_KEY_LMF);
2099         } else {
2100                 /*
2101                  * Emit IR to pop the LMF:
2102                  * *(lmf->lmf_addr) = lmf->prev_lmf
2103                  */
2104                 /* This could be called before emit_push_lmf () */
2105                 if (!cfg->lmf_addr_var)
2106                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2107                 lmf_addr_reg = cfg->lmf_addr_var->dreg;
2108
2109                 prev_lmf_reg = alloc_preg (cfg);
2110                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2111                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, prev_lmf_reg);
2112         }
2113 }
2114
2115 static void
2116 emit_instrumentation_call (MonoCompile *cfg, void *func)
2117 {
2118         MonoInst *iargs [1];
2119
2120         /*
2121          * Avoid instrumenting inlined methods since it can
2122          * distort profiling results.
2123          */
2124         if (cfg->method != cfg->current_method)
2125                 return;
2126
2127         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
2128                 EMIT_NEW_METHODCONST (cfg, iargs [0], cfg->method);
2129                 mono_emit_jit_icall (cfg, func, iargs);
2130         }
2131 }
2132
2133 static int
2134 ret_type_to_call_opcode (MonoCompile *cfg, MonoType *type, int calli, int virt)
2135 {
2136 handle_enum:
2137         type = mini_get_underlying_type (type);
2138         switch (type->type) {
2139         case MONO_TYPE_VOID:
2140                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALL_MEMBASE: OP_VOIDCALL;
2141         case MONO_TYPE_I1:
2142         case MONO_TYPE_U1:
2143         case MONO_TYPE_I2:
2144         case MONO_TYPE_U2:
2145         case MONO_TYPE_I4:
2146         case MONO_TYPE_U4:
2147                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2148         case MONO_TYPE_I:
2149         case MONO_TYPE_U:
2150         case MONO_TYPE_PTR:
2151         case MONO_TYPE_FNPTR:
2152                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2153         case MONO_TYPE_CLASS:
2154         case MONO_TYPE_STRING:
2155         case MONO_TYPE_OBJECT:
2156         case MONO_TYPE_SZARRAY:
2157         case MONO_TYPE_ARRAY:    
2158                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2159         case MONO_TYPE_I8:
2160         case MONO_TYPE_U8:
2161                 return calli? OP_LCALL_REG: virt? OP_LCALL_MEMBASE: OP_LCALL;
2162         case MONO_TYPE_R4:
2163                 if (cfg->r4fp)
2164                         return calli? OP_RCALL_REG: virt? OP_RCALL_MEMBASE: OP_RCALL;
2165                 else
2166                         return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2167         case MONO_TYPE_R8:
2168                 return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2169         case MONO_TYPE_VALUETYPE:
2170                 if (type->data.klass->enumtype) {
2171                         type = mono_class_enum_basetype (type->data.klass);
2172                         goto handle_enum;
2173                 } else
2174                         return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2175         case MONO_TYPE_TYPEDBYREF:
2176                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2177         case MONO_TYPE_GENERICINST:
2178                 type = &type->data.generic_class->container_class->byval_arg;
2179                 goto handle_enum;
2180         case MONO_TYPE_VAR:
2181         case MONO_TYPE_MVAR:
2182                 /* gsharedvt */
2183                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2184         default:
2185                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
2186         }
2187         return -1;
2188 }
2189
2190 /*
2191  * target_type_is_incompatible:
2192  * @cfg: MonoCompile context
2193  *
2194  * Check that the item @arg on the evaluation stack can be stored
2195  * in the target type (can be a local, or field, etc).
2196  * The cfg arg can be used to check if we need verification or just
2197  * validity checks.
2198  *
2199  * Returns: non-0 value if arg can't be stored on a target.
2200  */
2201 static int
2202 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
2203 {
2204         MonoType *simple_type;
2205         MonoClass *klass;
2206
2207         if (target->byref) {
2208                 /* FIXME: check that the pointed to types match */
2209                 if (arg->type == STACK_MP) {
2210                         MonoClass *base_class = mono_class_from_mono_type (target);
2211                         /* This is needed to handle gshared types + ldaddr */
2212                         simple_type = mini_get_underlying_type (&base_class->byval_arg);
2213                         return target->type != MONO_TYPE_I && arg->klass != base_class && arg->klass != mono_class_from_mono_type (simple_type);
2214                 }
2215                 if (arg->type == STACK_PTR)
2216                         return 0;
2217                 return 1;
2218         }
2219
2220         simple_type = mini_get_underlying_type (target);
2221         switch (simple_type->type) {
2222         case MONO_TYPE_VOID:
2223                 return 1;
2224         case MONO_TYPE_I1:
2225         case MONO_TYPE_U1:
2226         case MONO_TYPE_I2:
2227         case MONO_TYPE_U2:
2228         case MONO_TYPE_I4:
2229         case MONO_TYPE_U4:
2230                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2231                         return 1;
2232                 return 0;
2233         case MONO_TYPE_PTR:
2234                 /* STACK_MP is needed when setting pinned locals */
2235                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2236                         return 1;
2237                 return 0;
2238         case MONO_TYPE_I:
2239         case MONO_TYPE_U:
2240         case MONO_TYPE_FNPTR:
2241                 /* 
2242                  * Some opcodes like ldloca returns 'transient pointers' which can be stored in
2243                  * in native int. (#688008).
2244                  */
2245                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2246                         return 1;
2247                 return 0;
2248         case MONO_TYPE_CLASS:
2249         case MONO_TYPE_STRING:
2250         case MONO_TYPE_OBJECT:
2251         case MONO_TYPE_SZARRAY:
2252         case MONO_TYPE_ARRAY:    
2253                 if (arg->type != STACK_OBJ)
2254                         return 1;
2255                 /* FIXME: check type compatibility */
2256                 return 0;
2257         case MONO_TYPE_I8:
2258         case MONO_TYPE_U8:
2259                 if (arg->type != STACK_I8)
2260                         return 1;
2261                 return 0;
2262         case MONO_TYPE_R4:
2263                 if (arg->type != cfg->r4_stack_type)
2264                         return 1;
2265                 return 0;
2266         case MONO_TYPE_R8:
2267                 if (arg->type != STACK_R8)
2268                         return 1;
2269                 return 0;
2270         case MONO_TYPE_VALUETYPE:
2271                 if (arg->type != STACK_VTYPE)
2272                         return 1;
2273                 klass = mono_class_from_mono_type (simple_type);
2274                 if (klass != arg->klass)
2275                         return 1;
2276                 return 0;
2277         case MONO_TYPE_TYPEDBYREF:
2278                 if (arg->type != STACK_VTYPE)
2279                         return 1;
2280                 klass = mono_class_from_mono_type (simple_type);
2281                 if (klass != arg->klass)
2282                         return 1;
2283                 return 0;
2284         case MONO_TYPE_GENERICINST:
2285                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2286                         MonoClass *target_class;
2287                         if (arg->type != STACK_VTYPE)
2288                                 return 1;
2289                         klass = mono_class_from_mono_type (simple_type);
2290                         target_class = mono_class_from_mono_type (target);
2291                         /* The second cases is needed when doing partial sharing */
2292                         if (klass != arg->klass && target_class != arg->klass && target_class != mono_class_from_mono_type (mini_get_underlying_type (&arg->klass->byval_arg)))
2293                                 return 1;
2294                         return 0;
2295                 } else {
2296                         if (arg->type != STACK_OBJ)
2297                                 return 1;
2298                         /* FIXME: check type compatibility */
2299                         return 0;
2300                 }
2301         case MONO_TYPE_VAR:
2302         case MONO_TYPE_MVAR:
2303                 g_assert (cfg->gshared);
2304                 if (mini_type_var_is_vt (simple_type)) {
2305                         if (arg->type != STACK_VTYPE)
2306                                 return 1;
2307                 } else {
2308                         if (arg->type != STACK_OBJ)
2309                                 return 1;
2310                 }
2311                 return 0;
2312         default:
2313                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2314         }
2315         return 1;
2316 }
2317
2318 /*
2319  * Prepare arguments for passing to a function call.
2320  * Return a non-zero value if the arguments can't be passed to the given
2321  * signature.
2322  * The type checks are not yet complete and some conversions may need
2323  * casts on 32 or 64 bit architectures.
2324  *
2325  * FIXME: implement this using target_type_is_incompatible ()
2326  */
2327 static int
2328 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2329 {
2330         MonoType *simple_type;
2331         int i;
2332
2333         if (sig->hasthis) {
2334                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2335                         return 1;
2336                 args++;
2337         }
2338         for (i = 0; i < sig->param_count; ++i) {
2339                 if (sig->params [i]->byref) {
2340                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2341                                 return 1;
2342                         continue;
2343                 }
2344                 simple_type = mini_get_underlying_type (sig->params [i]);
2345 handle_enum:
2346                 switch (simple_type->type) {
2347                 case MONO_TYPE_VOID:
2348                         return 1;
2349                         continue;
2350                 case MONO_TYPE_I1:
2351                 case MONO_TYPE_U1:
2352                 case MONO_TYPE_I2:
2353                 case MONO_TYPE_U2:
2354                 case MONO_TYPE_I4:
2355                 case MONO_TYPE_U4:
2356                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2357                                 return 1;
2358                         continue;
2359                 case MONO_TYPE_I:
2360                 case MONO_TYPE_U:
2361                 case MONO_TYPE_PTR:
2362                 case MONO_TYPE_FNPTR:
2363                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2364                                 return 1;
2365                         continue;
2366                 case MONO_TYPE_CLASS:
2367                 case MONO_TYPE_STRING:
2368                 case MONO_TYPE_OBJECT:
2369                 case MONO_TYPE_SZARRAY:
2370                 case MONO_TYPE_ARRAY:    
2371                         if (args [i]->type != STACK_OBJ)
2372                                 return 1;
2373                         continue;
2374                 case MONO_TYPE_I8:
2375                 case MONO_TYPE_U8:
2376                         if (args [i]->type != STACK_I8)
2377                                 return 1;
2378                         continue;
2379                 case MONO_TYPE_R4:
2380                         if (args [i]->type != cfg->r4_stack_type)
2381                                 return 1;
2382                         continue;
2383                 case MONO_TYPE_R8:
2384                         if (args [i]->type != STACK_R8)
2385                                 return 1;
2386                         continue;
2387                 case MONO_TYPE_VALUETYPE:
2388                         if (simple_type->data.klass->enumtype) {
2389                                 simple_type = mono_class_enum_basetype (simple_type->data.klass);
2390                                 goto handle_enum;
2391                         }
2392                         if (args [i]->type != STACK_VTYPE)
2393                                 return 1;
2394                         continue;
2395                 case MONO_TYPE_TYPEDBYREF:
2396                         if (args [i]->type != STACK_VTYPE)
2397                                 return 1;
2398                         continue;
2399                 case MONO_TYPE_GENERICINST:
2400                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2401                         goto handle_enum;
2402                 case MONO_TYPE_VAR:
2403                 case MONO_TYPE_MVAR:
2404                         /* gsharedvt */
2405                         if (args [i]->type != STACK_VTYPE)
2406                                 return 1;
2407                         continue;
2408                 default:
2409                         g_error ("unknown type 0x%02x in check_call_signature",
2410                                  simple_type->type);
2411                 }
2412         }
2413         return 0;
2414 }
2415
2416 static int
2417 callvirt_to_call (int opcode)
2418 {
2419         switch (opcode) {
2420         case OP_CALL_MEMBASE:
2421                 return OP_CALL;
2422         case OP_VOIDCALL_MEMBASE:
2423                 return OP_VOIDCALL;
2424         case OP_FCALL_MEMBASE:
2425                 return OP_FCALL;
2426         case OP_RCALL_MEMBASE:
2427                 return OP_RCALL;
2428         case OP_VCALL_MEMBASE:
2429                 return OP_VCALL;
2430         case OP_LCALL_MEMBASE:
2431                 return OP_LCALL;
2432         default:
2433                 g_assert_not_reached ();
2434         }
2435
2436         return -1;
2437 }
2438
2439 static int
2440 callvirt_to_call_reg (int opcode)
2441 {
2442         switch (opcode) {
2443         case OP_CALL_MEMBASE:
2444                 return OP_CALL_REG;
2445         case OP_VOIDCALL_MEMBASE:
2446                 return OP_VOIDCALL_REG;
2447         case OP_FCALL_MEMBASE:
2448                 return OP_FCALL_REG;
2449         case OP_RCALL_MEMBASE:
2450                 return OP_RCALL_REG;
2451         case OP_VCALL_MEMBASE:
2452                 return OP_VCALL_REG;
2453         case OP_LCALL_MEMBASE:
2454                 return OP_LCALL_REG;
2455         default:
2456                 g_assert_not_reached ();
2457         }
2458
2459         return -1;
2460 }
2461
2462 /* Either METHOD or IMT_ARG needs to be set */
2463 static void
2464 emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoMethod *method, MonoInst *imt_arg)
2465 {
2466         int method_reg;
2467
2468         if (COMPILE_LLVM (cfg)) {
2469                 if (imt_arg) {
2470                         method_reg = alloc_preg (cfg);
2471                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2472                 } else {
2473                         MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
2474                         method_reg = ins->dreg;
2475                 }
2476
2477 #ifdef ENABLE_LLVM
2478                 call->imt_arg_reg = method_reg;
2479 #endif
2480                 mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2481                 return;
2482         }
2483
2484         if (imt_arg) {
2485                 method_reg = alloc_preg (cfg);
2486                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2487         } else {
2488                 MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
2489                 method_reg = ins->dreg;
2490         }
2491
2492         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2493 }
2494
2495 static MonoJumpInfo *
2496 mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpointer target)
2497 {
2498         MonoJumpInfo *ji = (MonoJumpInfo *)mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
2499
2500         ji->ip.i = ip;
2501         ji->type = type;
2502         ji->data.target = target;
2503
2504         return ji;
2505 }
2506
2507 static int
2508 mini_class_check_context_used (MonoCompile *cfg, MonoClass *klass)
2509 {
2510         if (cfg->gshared)
2511                 return mono_class_check_context_used (klass);
2512         else
2513                 return 0;
2514 }
2515
2516 static int
2517 mini_method_check_context_used (MonoCompile *cfg, MonoMethod *method)
2518 {
2519         if (cfg->gshared)
2520                 return mono_method_check_context_used (method);
2521         else
2522                 return 0;
2523 }
2524
2525 /*
2526  * check_method_sharing:
2527  *
2528  *   Check whenever the vtable or an mrgctx needs to be passed when calling CMETHOD.
2529  */
2530 static void
2531 check_method_sharing (MonoCompile *cfg, MonoMethod *cmethod, gboolean *out_pass_vtable, gboolean *out_pass_mrgctx)
2532 {
2533         gboolean pass_vtable = FALSE;
2534         gboolean pass_mrgctx = FALSE;
2535
2536         if (((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
2537                 (cmethod->klass->generic_class || cmethod->klass->generic_container)) {
2538                 gboolean sharable = FALSE;
2539
2540                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE))
2541                         sharable = TRUE;
2542
2543                 /*
2544                  * Pass vtable iff target method might
2545                  * be shared, which means that sharing
2546                  * is enabled for its class and its
2547                  * context is sharable (and it's not a
2548                  * generic method).
2549                  */
2550                 if (sharable && !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
2551                         pass_vtable = TRUE;
2552         }
2553
2554         if (mini_method_get_context (cmethod) &&
2555                 mini_method_get_context (cmethod)->method_inst) {
2556                 g_assert (!pass_vtable);
2557
2558                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE)) {
2559                         pass_mrgctx = TRUE;
2560                 } else {
2561                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (mono_method_signature (cmethod)))
2562                                 pass_mrgctx = TRUE;
2563                 }
2564         }
2565
2566         if (out_pass_vtable)
2567                 *out_pass_vtable = pass_vtable;
2568         if (out_pass_mrgctx)
2569                 *out_pass_mrgctx = pass_mrgctx;
2570 }
2571
2572 inline static MonoCallInst *
2573 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
2574                                          MonoInst **args, int calli, int virtual_, int tail, int rgctx, int unbox_trampoline)
2575 {
2576         MonoType *sig_ret;
2577         MonoCallInst *call;
2578 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2579         int i;
2580 #endif
2581
2582         if (cfg->llvm_only)
2583                 tail = FALSE;
2584
2585         if (tail) {
2586                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
2587
2588                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
2589         } else
2590                 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (cfg, sig->ret, calli, virtual_));
2591
2592         call->args = args;
2593         call->signature = sig;
2594         call->rgctx_reg = rgctx;
2595         sig_ret = mini_get_underlying_type (sig->ret);
2596
2597         type_to_eval_stack_type ((cfg), sig_ret, &call->inst);
2598
2599         if (tail) {
2600                 if (mini_type_is_vtype (sig_ret)) {
2601                         call->vret_var = cfg->vret_addr;
2602                         //g_assert_not_reached ();
2603                 }
2604         } else if (mini_type_is_vtype (sig_ret)) {
2605                 MonoInst *temp = mono_compile_create_var (cfg, sig_ret, OP_LOCAL);
2606                 MonoInst *loada;
2607
2608                 temp->backend.is_pinvoke = sig->pinvoke;
2609
2610                 /*
2611                  * We use a new opcode OP_OUTARG_VTRETADDR instead of LDADDR for emitting the
2612                  * address of return value to increase optimization opportunities.
2613                  * Before vtype decomposition, the dreg of the call ins itself represents the
2614                  * fact the call modifies the return value. After decomposition, the call will
2615                  * be transformed into one of the OP_VOIDCALL opcodes, and the VTRETADDR opcode
2616                  * will be transformed into an LDADDR.
2617                  */
2618                 MONO_INST_NEW (cfg, loada, OP_OUTARG_VTRETADDR);
2619                 loada->dreg = alloc_preg (cfg);
2620                 loada->inst_p0 = temp;
2621                 /* We reference the call too since call->dreg could change during optimization */
2622                 loada->inst_p1 = call;
2623                 MONO_ADD_INS (cfg->cbb, loada);
2624
2625                 call->inst.dreg = temp->dreg;
2626
2627                 call->vret_var = loada;
2628         } else if (!MONO_TYPE_IS_VOID (sig_ret))
2629                 call->inst.dreg = alloc_dreg (cfg, (MonoStackType)call->inst.type);
2630
2631 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2632         if (COMPILE_SOFT_FLOAT (cfg)) {
2633                 /* 
2634                  * If the call has a float argument, we would need to do an r8->r4 conversion using 
2635                  * an icall, but that cannot be done during the call sequence since it would clobber
2636                  * the call registers + the stack. So we do it before emitting the call.
2637                  */
2638                 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2639                         MonoType *t;
2640                         MonoInst *in = call->args [i];
2641
2642                         if (i >= sig->hasthis)
2643                                 t = sig->params [i - sig->hasthis];
2644                         else
2645                                 t = &mono_defaults.int_class->byval_arg;
2646                         t = mono_type_get_underlying_type (t);
2647
2648                         if (!t->byref && t->type == MONO_TYPE_R4) {
2649                                 MonoInst *iargs [1];
2650                                 MonoInst *conv;
2651
2652                                 iargs [0] = in;
2653                                 conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
2654
2655                                 /* The result will be in an int vreg */
2656                                 call->args [i] = conv;
2657                         }
2658                 }
2659         }
2660 #endif
2661
2662         call->need_unbox_trampoline = unbox_trampoline;
2663
2664 #ifdef ENABLE_LLVM
2665         if (COMPILE_LLVM (cfg))
2666                 mono_llvm_emit_call (cfg, call);
2667         else
2668                 mono_arch_emit_call (cfg, call);
2669 #else
2670         mono_arch_emit_call (cfg, call);
2671 #endif
2672
2673         cfg->param_area = MAX (cfg->param_area, call->stack_usage);
2674         cfg->flags |= MONO_CFG_HAS_CALLS;
2675         
2676         return call;
2677 }
2678
2679 static void
2680 set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rgctx_arg)
2681 {
2682         mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
2683         cfg->uses_rgctx_reg = TRUE;
2684         call->rgctx_reg = TRUE;
2685 #ifdef ENABLE_LLVM
2686         call->rgctx_arg_reg = rgctx_reg;
2687 #endif
2688 }       
2689
2690 inline static MonoInst*
2691 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg)
2692 {
2693         MonoCallInst *call;
2694         MonoInst *ins;
2695         int rgctx_reg = -1;
2696         gboolean check_sp = FALSE;
2697
2698         if (cfg->check_pinvoke_callconv && cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
2699                 WrapperInfo *info = mono_marshal_get_wrapper_info (cfg->method);
2700
2701                 if (info && info->subtype == WRAPPER_SUBTYPE_PINVOKE)
2702                         check_sp = TRUE;
2703         }
2704
2705         if (rgctx_arg) {
2706                 rgctx_reg = mono_alloc_preg (cfg);
2707                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2708         }
2709
2710         if (check_sp) {
2711                 if (!cfg->stack_inbalance_var)
2712                         cfg->stack_inbalance_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2713
2714                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2715                 ins->dreg = cfg->stack_inbalance_var->dreg;
2716                 MONO_ADD_INS (cfg->cbb, ins);
2717         }
2718
2719         call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE);
2720
2721         call->inst.sreg1 = addr->dreg;
2722
2723         if (imt_arg)
2724                 emit_imt_argument (cfg, call, NULL, imt_arg);
2725
2726         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2727
2728         if (check_sp) {
2729                 int sp_reg;
2730
2731                 sp_reg = mono_alloc_preg (cfg);
2732
2733                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2734                 ins->dreg = sp_reg;
2735                 MONO_ADD_INS (cfg->cbb, ins);
2736
2737                 /* Restore the stack so we don't crash when throwing the exception */
2738                 MONO_INST_NEW (cfg, ins, OP_SET_SP);
2739                 ins->sreg1 = cfg->stack_inbalance_var->dreg;
2740                 MONO_ADD_INS (cfg->cbb, ins);
2741
2742                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, cfg->stack_inbalance_var->dreg, sp_reg);
2743                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ExecutionEngineException");
2744         }
2745
2746         if (rgctx_arg)
2747                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2748
2749         return (MonoInst*)call;
2750 }
2751
2752 static MonoInst*
2753 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2754
2755 static MonoInst*
2756 emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type);
2757 static MonoInst*
2758 emit_get_rgctx_klass (MonoCompile *cfg, int context_used, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2759
2760 static MonoInst*
2761 mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig, gboolean tail,
2762                                                         MonoInst **args, MonoInst *this_ins, MonoInst *imt_arg, MonoInst *rgctx_arg)
2763 {
2764 #ifndef DISABLE_REMOTING
2765         gboolean might_be_remote = FALSE;
2766 #endif
2767         gboolean virtual_ = this_ins != NULL;
2768         gboolean enable_for_aot = TRUE;
2769         int context_used;
2770         MonoCallInst *call;
2771         MonoInst *call_target = NULL;
2772         int rgctx_reg = 0;
2773         gboolean need_unbox_trampoline;
2774
2775         if (!sig)
2776                 sig = mono_method_signature (method);
2777
2778         if (cfg->llvm_only && (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE))
2779                 g_assert_not_reached ();
2780
2781         if (rgctx_arg) {
2782                 rgctx_reg = mono_alloc_preg (cfg);
2783                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2784         }
2785
2786         if (method->string_ctor) {
2787                 /* Create the real signature */
2788                 /* FIXME: Cache these */
2789                 MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_mempool (cfg->mempool, sig);
2790                 ctor_sig->ret = &mono_defaults.string_class->byval_arg;
2791
2792                 sig = ctor_sig;
2793         }
2794
2795         context_used = mini_method_check_context_used (cfg, method);
2796
2797 #ifndef DISABLE_REMOTING
2798         might_be_remote = this_ins && sig->hasthis &&
2799                 (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) &&
2800                 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && (!MONO_CHECK_THIS (this_ins) || context_used);
2801
2802         if (might_be_remote && context_used) {
2803                 MonoInst *addr;
2804
2805                 g_assert (cfg->gshared);
2806
2807                 addr = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK);
2808
2809                 return mono_emit_calli (cfg, sig, args, addr, NULL, NULL);
2810         }
2811 #endif
2812
2813         if (cfg->llvm_only && !call_target && virtual_ && (method->flags & METHOD_ATTRIBUTE_VIRTUAL))
2814                 return emit_llvmonly_virtual_call (cfg, method, sig, 0, args);
2815
2816         need_unbox_trampoline = method->klass == mono_defaults.object_class || (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
2817
2818         call = mono_emit_call_args (cfg, sig, args, FALSE, virtual_, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline);
2819
2820 #ifndef DISABLE_REMOTING
2821         if (might_be_remote)
2822                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2823         else
2824 #endif
2825                 call->method = method;
2826         call->inst.flags |= MONO_INST_HAS_METHOD;
2827         call->inst.inst_left = this_ins;
2828         call->tail_call = tail;
2829
2830         if (virtual_) {
2831                 int vtable_reg, slot_reg, this_reg;
2832                 int offset;
2833
2834                 this_reg = this_ins->dreg;
2835
2836                 if (!cfg->llvm_only && (method->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (method->name, "Invoke")) {
2837                         MonoInst *dummy_use;
2838
2839                         MONO_EMIT_NULL_CHECK (cfg, this_reg);
2840
2841                         /* Make a call to delegate->invoke_impl */
2842                         call->inst.inst_basereg = this_reg;
2843                         call->inst.inst_offset = MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl);
2844                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2845
2846                         /* We must emit a dummy use here because the delegate trampoline will
2847                         replace the 'this' argument with the delegate target making this activation
2848                         no longer a root for the delegate.
2849                         This is an issue for delegates that target collectible code such as dynamic
2850                         methods of GC'able assemblies.
2851
2852                         For a test case look into #667921.
2853
2854                         FIXME: a dummy use is not the best way to do it as the local register allocator
2855                         will put it on a caller save register and spil it around the call. 
2856                         Ideally, we would either put it on a callee save register or only do the store part.  
2857                          */
2858                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [0]);
2859
2860                         return (MonoInst*)call;
2861                 }
2862
2863                 if ((!cfg->compile_aot || enable_for_aot) && 
2864                         (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
2865                          (MONO_METHOD_IS_FINAL (method) &&
2866                           method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)) &&
2867                         !(mono_class_is_marshalbyref (method->klass) && context_used)) {
2868                         /* 
2869                          * the method is not virtual, we just need to ensure this is not null
2870                          * and then we can call the method directly.
2871                          */
2872 #ifndef DISABLE_REMOTING
2873                         if (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) {
2874                                 /* 
2875                                  * The check above ensures method is not gshared, this is needed since
2876                                  * gshared methods can't have wrappers.
2877                                  */
2878                                 method = call->method = mono_marshal_get_remoting_invoke_with_check (method);
2879                         }
2880 #endif
2881
2882                         if (!method->string_ctor)
2883                                 MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2884
2885                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2886                 } else if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && MONO_METHOD_IS_FINAL (method)) {
2887                         /*
2888                          * the method is virtual, but we can statically dispatch since either
2889                          * it's class or the method itself are sealed.
2890                          * But first we need to ensure it's not a null reference.
2891                          */
2892                         MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2893
2894                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2895                 } else if (call_target) {
2896                         vtable_reg = alloc_preg (cfg);
2897                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2898
2899                         call->inst.opcode = callvirt_to_call_reg (call->inst.opcode);
2900                         call->inst.sreg1 = call_target->dreg;
2901                         call->inst.flags &= !MONO_INST_HAS_METHOD;
2902                 } else {
2903                         vtable_reg = alloc_preg (cfg);
2904                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2905                         if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2906                                 guint32 imt_slot = mono_method_get_imt_slot (method);
2907                                 emit_imt_argument (cfg, call, call->method, imt_arg);
2908                                 slot_reg = vtable_reg;
2909                                 offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
2910                         } else {
2911                                 slot_reg = vtable_reg;
2912                                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) +
2913                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
2914                                 if (imt_arg) {
2915                                         g_assert (mono_method_signature (method)->generic_param_count);
2916                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2917                                 }
2918                         }
2919
2920                         call->inst.sreg1 = slot_reg;
2921                         call->inst.inst_offset = offset;
2922                         call->is_virtual = TRUE;
2923                 }
2924         }
2925
2926         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2927
2928         if (rgctx_arg)
2929                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2930
2931         return (MonoInst*)call;
2932 }
2933
2934 MonoInst*
2935 mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this_ins)
2936 {
2937         return mono_emit_method_call_full (cfg, method, mono_method_signature (method), FALSE, args, this_ins, NULL, NULL);
2938 }
2939
2940 MonoInst*
2941 mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig,
2942                                            MonoInst **args)
2943 {
2944         MonoCallInst *call;
2945
2946         g_assert (sig);
2947
2948         call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE, FALSE, FALSE);
2949         call->fptr = func;
2950
2951         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2952
2953         return (MonoInst*)call;
2954 }
2955
2956 MonoInst*
2957 mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args)
2958 {
2959         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2960
2961         g_assert (info);
2962
2963         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2964 }
2965
2966 /*
2967  * mono_emit_abs_call:
2968  *
2969  *   Emit a call to the runtime function described by PATCH_TYPE and DATA.
2970  */
2971 inline static MonoInst*
2972 mono_emit_abs_call (MonoCompile *cfg, MonoJumpInfoType patch_type, gconstpointer data, 
2973                                         MonoMethodSignature *sig, MonoInst **args)
2974 {
2975         MonoJumpInfo *ji = mono_patch_info_new (cfg->mempool, 0, patch_type, data);
2976         MonoInst *ins;
2977
2978         /* 
2979          * We pass ji as the call address, the PATCH_INFO_ABS resolving code will
2980          * handle it.
2981          */
2982         if (cfg->abs_patches == NULL)
2983                 cfg->abs_patches = g_hash_table_new (NULL, NULL);
2984         g_hash_table_insert (cfg->abs_patches, ji, ji);
2985         ins = mono_emit_native_call (cfg, ji, sig, args);
2986         ((MonoCallInst*)ins)->fptr_is_patch = TRUE;
2987         return ins;
2988 }
2989
2990 static MonoMethodSignature*
2991 sig_to_rgctx_sig (MonoMethodSignature *sig)
2992 {
2993         // FIXME: memory allocation
2994         MonoMethodSignature *res;
2995         int i;
2996
2997         res = (MonoMethodSignature *)g_malloc (MONO_SIZEOF_METHOD_SIGNATURE + (sig->param_count + 1) * sizeof (MonoType*));
2998         memcpy (res, sig, MONO_SIZEOF_METHOD_SIGNATURE);
2999         res->param_count = sig->param_count + 1;
3000         for (i = 0; i < sig->param_count; ++i)
3001                 res->params [i] = sig->params [i];
3002         res->params [sig->param_count] = &mono_defaults.int_class->this_arg;
3003         return res;
3004 }
3005
3006 /* Make an indirect call to FSIG passing an additional argument */
3007 static MonoInst*
3008 emit_extra_arg_calli (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **orig_args, int arg_reg, MonoInst *call_target)
3009 {
3010         MonoMethodSignature *csig;
3011         MonoInst *args_buf [16];
3012         MonoInst **args;
3013         int i, pindex, tmp_reg;
3014
3015         /* Make a call with an rgctx/extra arg */
3016         if (fsig->param_count + 2 < 16)
3017                 args = args_buf;
3018         else
3019                 args = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (fsig->param_count + 2));
3020         pindex = 0;
3021         if (fsig->hasthis)
3022                 args [pindex ++] = orig_args [0];
3023         for (i = 0; i < fsig->param_count; ++i)
3024                 args [pindex ++] = orig_args [fsig->hasthis + i];
3025         tmp_reg = alloc_preg (cfg);
3026         EMIT_NEW_UNALU (cfg, args [pindex], OP_MOVE, tmp_reg, arg_reg);
3027         csig = sig_to_rgctx_sig (fsig);
3028         return mono_emit_calli (cfg, csig, args, call_target, NULL, NULL);
3029 }
3030
3031 /* Emit an indirect call to the function descriptor ADDR */
3032 static MonoInst*
3033 emit_llvmonly_calli (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, MonoInst *addr)
3034 {
3035         int addr_reg, arg_reg;
3036         MonoInst *call_target;
3037
3038         g_assert (cfg->llvm_only);
3039
3040         /*
3041          * addr points to a <addr, arg> pair, load both of them, and
3042          * make a call to addr, passing arg as an extra arg.
3043          */
3044         addr_reg = alloc_preg (cfg);
3045         EMIT_NEW_LOAD_MEMBASE (cfg, call_target, OP_LOAD_MEMBASE, addr_reg, addr->dreg, 0);
3046         arg_reg = alloc_preg (cfg);
3047         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, arg_reg, addr->dreg, sizeof (gpointer));
3048
3049         return emit_extra_arg_calli (cfg, fsig, args, arg_reg, call_target);
3050 }
3051
3052 static gboolean
3053 direct_icalls_enabled (MonoCompile *cfg)
3054 {
3055         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
3056 #ifdef TARGET_AMD64
3057         if (cfg->compile_llvm)
3058                 return FALSE;
3059 #endif
3060         if (cfg->gen_sdb_seq_points || cfg->disable_direct_icalls)
3061                 return FALSE;
3062         return TRUE;
3063 }
3064
3065 MonoInst*
3066 mono_emit_jit_icall_by_info (MonoCompile *cfg, MonoJitICallInfo *info, MonoInst **args)
3067 {
3068         /*
3069          * Call the jit icall without a wrapper if possible.
3070          * The wrapper is needed for the following reasons:
3071          * - to handle exceptions thrown using mono_raise_exceptions () from the
3072          *   icall function. The EH code needs the lmf frame pushed by the
3073          *   wrapper to be able to unwind back to managed code.
3074          * - to be able to do stack walks for asynchronously suspended
3075          *   threads when debugging.
3076          */
3077         if (info->no_raise && direct_icalls_enabled (cfg)) {
3078                 char *name;
3079                 int costs;
3080
3081                 if (!info->wrapper_method) {
3082                         name = g_strdup_printf ("__icall_wrapper_%s", info->name);
3083                         info->wrapper_method = mono_marshal_get_icall_wrapper (info->sig, name, info->func, TRUE);
3084                         g_free (name);
3085                         mono_memory_barrier ();
3086                 }
3087
3088                 /*
3089                  * Inline the wrapper method, which is basically a call to the C icall, and
3090                  * an exception check.
3091                  */
3092                 costs = inline_method (cfg, info->wrapper_method, NULL,
3093                                                            args, NULL, cfg->real_offset, TRUE);
3094                 g_assert (costs > 0);
3095                 g_assert (!MONO_TYPE_IS_VOID (info->sig->ret));
3096
3097                 return args [0];
3098         } else {
3099                 return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
3100         }
3101 }
3102  
3103 static MonoInst*
3104 mono_emit_widen_call_res (MonoCompile *cfg, MonoInst *ins, MonoMethodSignature *fsig)
3105 {
3106         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
3107                 if ((fsig->pinvoke || LLVM_ENABLED) && !fsig->ret->byref) {
3108                         int widen_op = -1;
3109
3110                         /* 
3111                          * Native code might return non register sized integers 
3112                          * without initializing the upper bits.
3113                          */
3114                         switch (mono_type_to_load_membase (cfg, fsig->ret)) {
3115                         case OP_LOADI1_MEMBASE:
3116                                 widen_op = OP_ICONV_TO_I1;
3117                                 break;
3118                         case OP_LOADU1_MEMBASE:
3119                                 widen_op = OP_ICONV_TO_U1;
3120                                 break;
3121                         case OP_LOADI2_MEMBASE:
3122                                 widen_op = OP_ICONV_TO_I2;
3123                                 break;
3124                         case OP_LOADU2_MEMBASE:
3125                                 widen_op = OP_ICONV_TO_U2;
3126                                 break;
3127                         default:
3128                                 break;
3129                         }
3130
3131                         if (widen_op != -1) {
3132                                 int dreg = alloc_preg (cfg);
3133                                 MonoInst *widen;
3134
3135                                 EMIT_NEW_UNALU (cfg, widen, widen_op, dreg, ins->dreg);
3136                                 widen->type = ins->type;
3137                                 ins = widen;
3138                         }
3139                 }
3140         }
3141
3142         return ins;
3143 }
3144
3145 static MonoMethod*
3146 get_memcpy_method (void)
3147 {
3148         static MonoMethod *memcpy_method = NULL;
3149         if (!memcpy_method) {
3150                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
3151                 if (!memcpy_method)
3152                         g_error ("Old corlib found. Install a new one");
3153         }
3154         return memcpy_method;
3155 }
3156
3157 static void
3158 create_write_barrier_bitmap (MonoCompile *cfg, MonoClass *klass, unsigned *wb_bitmap, int offset)
3159 {
3160         MonoClassField *field;
3161         gpointer iter = NULL;
3162
3163         while ((field = mono_class_get_fields (klass, &iter))) {
3164                 int foffset;
3165
3166                 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3167                         continue;
3168                 foffset = klass->valuetype ? field->offset - sizeof (MonoObject): field->offset;
3169                 if (mini_type_is_reference (mono_field_get_type (field))) {
3170                         g_assert ((foffset % SIZEOF_VOID_P) == 0);
3171                         *wb_bitmap |= 1 << ((offset + foffset) / SIZEOF_VOID_P);
3172                 } else {
3173                         MonoClass *field_class = mono_class_from_mono_type (field->type);
3174                         if (field_class->has_references)
3175                                 create_write_barrier_bitmap (cfg, field_class, wb_bitmap, offset + foffset);
3176                 }
3177         }
3178 }
3179
3180 static void
3181 emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value)
3182 {
3183         int card_table_shift_bits;
3184         gpointer card_table_mask;
3185         guint8 *card_table;
3186         MonoInst *dummy_use;
3187         int nursery_shift_bits;
3188         size_t nursery_size;
3189
3190         if (!cfg->gen_write_barriers)
3191                 return;
3192
3193         card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
3194
3195         mono_gc_get_nursery (&nursery_shift_bits, &nursery_size);
3196
3197         if (cfg->backend->have_card_table_wb && !cfg->compile_aot && card_table && nursery_shift_bits > 0 && !COMPILE_LLVM (cfg)) {
3198                 MonoInst *wbarrier;
3199
3200                 MONO_INST_NEW (cfg, wbarrier, OP_CARD_TABLE_WBARRIER);
3201                 wbarrier->sreg1 = ptr->dreg;
3202                 wbarrier->sreg2 = value->dreg;
3203                 MONO_ADD_INS (cfg->cbb, wbarrier);
3204         } else if (card_table && !cfg->compile_aot && !mono_gc_card_table_nursery_check ()) {
3205                 int offset_reg = alloc_preg (cfg);
3206                 int card_reg;
3207                 MonoInst *ins;
3208
3209                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, offset_reg, ptr->dreg, card_table_shift_bits);
3210                 if (card_table_mask)
3211                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, offset_reg, offset_reg, card_table_mask);
3212
3213                 /*We can't use PADD_IMM since the cardtable might end up in high addresses and amd64 doesn't support
3214                  * IMM's larger than 32bits.
3215                  */
3216                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
3217                 card_reg = ins->dreg;
3218
3219                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, offset_reg, offset_reg, card_reg);
3220                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, offset_reg, 0, 1);
3221         } else {
3222                 MonoMethod *write_barrier = mono_gc_get_write_barrier ();
3223                 mono_emit_method_call (cfg, write_barrier, &ptr, NULL);
3224         }
3225
3226         EMIT_NEW_DUMMY_USE (cfg, dummy_use, value);
3227 }
3228
3229 static gboolean
3230 mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align)
3231 {
3232         int dest_ptr_reg, tmp_reg, destreg, srcreg, offset;
3233         unsigned need_wb = 0;
3234
3235         if (align == 0)
3236                 align = 4;
3237
3238         /*types with references can't have alignment smaller than sizeof(void*) */
3239         if (align < SIZEOF_VOID_P)
3240                 return FALSE;
3241
3242         /*This value cannot be bigger than 32 due to the way we calculate the required wb bitmap.*/
3243         if (size > 32 * SIZEOF_VOID_P)
3244                 return FALSE;
3245
3246         create_write_barrier_bitmap (cfg, klass, &need_wb, 0);
3247
3248         /* We don't unroll more than 5 stores to avoid code bloat. */
3249         if (size > 5 * SIZEOF_VOID_P) {
3250                 /*This is harmless and simplify mono_gc_wbarrier_value_copy_bitmap */
3251                 size += (SIZEOF_VOID_P - 1);
3252                 size &= ~(SIZEOF_VOID_P - 1);
3253
3254                 EMIT_NEW_ICONST (cfg, iargs [2], size);
3255                 EMIT_NEW_ICONST (cfg, iargs [3], need_wb);
3256                 mono_emit_jit_icall (cfg, mono_gc_wbarrier_value_copy_bitmap, iargs);
3257                 return TRUE;
3258         }
3259
3260         destreg = iargs [0]->dreg;
3261         srcreg = iargs [1]->dreg;
3262         offset = 0;
3263
3264         dest_ptr_reg = alloc_preg (cfg);
3265         tmp_reg = alloc_preg (cfg);
3266
3267         /*tmp = dreg*/
3268         EMIT_NEW_UNALU (cfg, iargs [0], OP_MOVE, dest_ptr_reg, destreg);
3269
3270         while (size >= SIZEOF_VOID_P) {
3271                 MonoInst *load_inst;
3272                 MONO_INST_NEW (cfg, load_inst, OP_LOAD_MEMBASE);
3273                 load_inst->dreg = tmp_reg;
3274                 load_inst->inst_basereg = srcreg;
3275                 load_inst->inst_offset = offset;
3276                 MONO_ADD_INS (cfg->cbb, load_inst);
3277
3278                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg);
3279
3280                 if (need_wb & 0x1)
3281                         emit_write_barrier (cfg, iargs [0], load_inst);
3282
3283                 offset += SIZEOF_VOID_P;
3284                 size -= SIZEOF_VOID_P;
3285                 need_wb >>= 1;
3286
3287                 /*tmp += sizeof (void*)*/
3288                 if (size >= SIZEOF_VOID_P) {
3289                         NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dest_ptr_reg, dest_ptr_reg, SIZEOF_VOID_P);
3290                         MONO_ADD_INS (cfg->cbb, iargs [0]);
3291                 }
3292         }
3293
3294         /* Those cannot be references since size < sizeof (void*) */
3295         while (size >= 4) {
3296                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tmp_reg, srcreg, offset);
3297                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, tmp_reg);
3298                 offset += 4;
3299                 size -= 4;
3300         }
3301
3302         while (size >= 2) {
3303                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmp_reg, srcreg, offset);
3304                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, tmp_reg);
3305                 offset += 2;
3306                 size -= 2;
3307         }
3308
3309         while (size >= 1) {
3310                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmp_reg, srcreg, offset);
3311                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, tmp_reg);
3312                 offset += 1;
3313                 size -= 1;
3314         }
3315
3316         return TRUE;
3317 }
3318
3319 /*
3320  * Emit code to copy a valuetype of type @klass whose address is stored in
3321  * @src->dreg to memory whose address is stored at @dest->dreg.
3322  */
3323 void
3324 mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native)
3325 {
3326         MonoInst *iargs [4];
3327         int n;
3328         guint32 align = 0;
3329         MonoMethod *memcpy_method;
3330         MonoInst *size_ins = NULL;
3331         MonoInst *memcpy_ins = NULL;
3332
3333         g_assert (klass);
3334         if (cfg->gshared)
3335                 klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
3336
3337         /*
3338          * This check breaks with spilled vars... need to handle it during verification anyway.
3339          * g_assert (klass && klass == src->klass && klass == dest->klass);
3340          */
3341
3342         if (mini_is_gsharedvt_klass (klass)) {
3343                 g_assert (!native);
3344                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3345                 memcpy_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_MEMCPY);
3346         }
3347
3348         if (native)
3349                 n = mono_class_native_size (klass, &align);
3350         else
3351                 n = mono_class_value_size (klass, &align);
3352
3353         /* if native is true there should be no references in the struct */
3354         if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) {
3355                 /* Avoid barriers when storing to the stack */
3356                 if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
3357                           (dest->opcode == OP_LDADDR))) {
3358                         int context_used;
3359
3360                         iargs [0] = dest;
3361                         iargs [1] = src;
3362
3363                         context_used = mini_class_check_context_used (cfg, klass);
3364
3365                         /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
3366                         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
3367                                 return;
3368                         } else if (context_used) {
3369                                 iargs [2] = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3370                         }  else {
3371                                 iargs [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
3372                                 if (!cfg->compile_aot)
3373                                         mono_class_compute_gc_descriptor (klass);
3374                         }
3375
3376                         if (size_ins)
3377                                 mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
3378                         else
3379                                 mono_emit_jit_icall (cfg, mono_value_copy, iargs);
3380                         return;
3381                 }
3382         }
3383
3384         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 8) {
3385                 /* FIXME: Optimize the case when src/dest is OP_LDADDR */
3386                 mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, n, align);
3387         } else {
3388                 iargs [0] = dest;
3389                 iargs [1] = src;
3390                 if (size_ins)
3391                         iargs [2] = size_ins;
3392                 else
3393                         EMIT_NEW_ICONST (cfg, iargs [2], n);
3394                 
3395                 memcpy_method = get_memcpy_method ();
3396                 if (memcpy_ins)
3397                         mono_emit_calli (cfg, mono_method_signature (memcpy_method), iargs, memcpy_ins, NULL, NULL);
3398                 else
3399                         mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
3400         }
3401 }
3402
3403 static MonoMethod*
3404 get_memset_method (void)
3405 {
3406         static MonoMethod *memset_method = NULL;
3407         if (!memset_method) {
3408                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
3409                 if (!memset_method)
3410                         g_error ("Old corlib found. Install a new one");
3411         }
3412         return memset_method;
3413 }
3414
3415 void
3416 mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass)
3417 {
3418         MonoInst *iargs [3];
3419         int n;
3420         guint32 align;
3421         MonoMethod *memset_method;
3422         MonoInst *size_ins = NULL;
3423         MonoInst *bzero_ins = NULL;
3424         static MonoMethod *bzero_method;
3425
3426         /* FIXME: Optimize this for the case when dest is an LDADDR */
3427         mono_class_init (klass);
3428         if (mini_is_gsharedvt_klass (klass)) {
3429                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3430                 bzero_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_BZERO);
3431                 if (!bzero_method)
3432                         bzero_method = mono_class_get_method_from_name (mono_defaults.string_class, "bzero_aligned_1", 2);
3433                 g_assert (bzero_method);
3434                 iargs [0] = dest;
3435                 iargs [1] = size_ins;
3436                 mono_emit_calli (cfg, mono_method_signature (bzero_method), iargs, bzero_ins, NULL, NULL);
3437                 return;
3438         }
3439
3440         klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
3441
3442         n = mono_class_value_size (klass, &align);
3443
3444         if (n <= sizeof (gpointer) * 8) {
3445                 mini_emit_memset (cfg, dest->dreg, 0, n, 0, align);
3446         }
3447         else {
3448                 memset_method = get_memset_method ();
3449                 iargs [0] = dest;
3450                 EMIT_NEW_ICONST (cfg, iargs [1], 0);
3451                 EMIT_NEW_ICONST (cfg, iargs [2], n);
3452                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
3453         }
3454 }
3455
3456 /*
3457  * emit_get_rgctx:
3458  *
3459  *   Emit IR to return either the this pointer for instance method,
3460  * or the mrgctx for static methods.
3461  */
3462 static MonoInst*
3463 emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used)
3464 {
3465         MonoInst *this_ins = NULL;
3466
3467         g_assert (cfg->gshared);
3468
3469         if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&
3470                         !(context_used & MONO_GENERIC_CONTEXT_USED_METHOD) &&
3471                         !method->klass->valuetype)
3472                 EMIT_NEW_ARGLOAD (cfg, this_ins, 0);
3473
3474         if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
3475                 MonoInst *mrgctx_loc, *mrgctx_var;
3476
3477                 g_assert (!this_ins);
3478                 g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
3479
3480                 mrgctx_loc = mono_get_vtable_var (cfg);
3481                 EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
3482
3483                 return mrgctx_var;
3484         } else if (method->flags & METHOD_ATTRIBUTE_STATIC || method->klass->valuetype) {
3485                 MonoInst *vtable_loc, *vtable_var;
3486
3487                 g_assert (!this_ins);
3488
3489                 vtable_loc = mono_get_vtable_var (cfg);
3490                 EMIT_NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
3491
3492                 if (method->is_inflated && mono_method_get_context (method)->method_inst) {
3493                         MonoInst *mrgctx_var = vtable_var;
3494                         int vtable_reg;
3495
3496                         vtable_reg = alloc_preg (cfg);
3497                         EMIT_NEW_LOAD_MEMBASE (cfg, vtable_var, OP_LOAD_MEMBASE, vtable_reg, mrgctx_var->dreg, MONO_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable));
3498                         vtable_var->type = STACK_PTR;
3499                 }
3500
3501                 return vtable_var;
3502         } else {
3503                 MonoInst *ins;
3504                 int vtable_reg;
3505         
3506                 vtable_reg = alloc_preg (cfg);
3507                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, vtable_reg, this_ins->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3508                 return ins;
3509         }
3510 }
3511
3512 static MonoJumpInfoRgctxEntry *
3513 mono_patch_info_rgctx_entry_new (MonoMemPool *mp, MonoMethod *method, gboolean in_mrgctx, MonoJumpInfoType patch_type, gconstpointer patch_data, MonoRgctxInfoType info_type)
3514 {
3515         MonoJumpInfoRgctxEntry *res = (MonoJumpInfoRgctxEntry *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoRgctxEntry));
3516         res->method = method;
3517         res->in_mrgctx = in_mrgctx;
3518         res->data = (MonoJumpInfo *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
3519         res->data->type = patch_type;
3520         res->data->data.target = patch_data;
3521         res->info_type = info_type;
3522
3523         return res;
3524 }
3525
3526 static inline MonoInst*
3527 emit_rgctx_fetch_inline (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3528 {
3529         MonoInst *args [16];
3530         MonoInst *call;
3531
3532         // FIXME: No fastpath since the slot is not a compile time constant
3533         args [0] = rgctx;
3534         EMIT_NEW_AOTCONST (cfg, args [1], MONO_PATCH_INFO_RGCTX_SLOT_INDEX, entry);
3535         if (entry->in_mrgctx)
3536                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3537         else
3538                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3539         return call;
3540 #if 0
3541         /*
3542          * FIXME: This can be called during decompose, which is a problem since it creates
3543          * new bblocks.
3544          * Also, the fastpath doesn't work since the slot number is dynamically allocated.
3545          */
3546         int i, slot, depth, index, rgctx_reg, val_reg, res_reg;
3547         gboolean mrgctx;
3548         MonoBasicBlock *is_null_bb, *end_bb;
3549         MonoInst *res, *ins, *call;
3550         MonoInst *args[16];
3551
3552         slot = mini_get_rgctx_entry_slot (entry);
3553
3554         mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot);
3555         index = MONO_RGCTX_SLOT_INDEX (slot);
3556         if (mrgctx)
3557                 index += MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
3558         for (depth = 0; ; ++depth) {
3559                 int size = mono_class_rgctx_get_array_size (depth, mrgctx);
3560
3561                 if (index < size - 1)
3562                         break;
3563                 index -= size - 1;
3564         }
3565
3566         NEW_BBLOCK (cfg, end_bb);
3567         NEW_BBLOCK (cfg, is_null_bb);
3568
3569         if (mrgctx) {
3570                 rgctx_reg = rgctx->dreg;
3571         } else {
3572                 rgctx_reg = alloc_preg (cfg);
3573
3574                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, rgctx_reg, rgctx->dreg, MONO_STRUCT_OFFSET (MonoVTable, runtime_generic_context));
3575                 // FIXME: Avoid this check by allocating the table when the vtable is created etc.
3576                 NEW_BBLOCK (cfg, is_null_bb);
3577
3578                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3579                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3580         }
3581
3582         for (i = 0; i < depth; ++i) {
3583                 int array_reg = alloc_preg (cfg);
3584
3585                 /* load ptr to next array */
3586                 if (mrgctx && i == 0)
3587                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT);
3588                 else
3589                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, 0);
3590                 rgctx_reg = array_reg;
3591                 /* is the ptr null? */
3592                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3593                 /* if yes, jump to actual trampoline */
3594                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3595         }
3596
3597         /* fetch slot */
3598         val_reg = alloc_preg (cfg);
3599         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, val_reg, rgctx_reg, (index + 1) * sizeof (gpointer));
3600         /* is the slot null? */
3601         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, val_reg, 0);
3602         /* if yes, jump to actual trampoline */
3603         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3604
3605         /* Fastpath */
3606         res_reg = alloc_preg (cfg);
3607         MONO_INST_NEW (cfg, ins, OP_MOVE);
3608         ins->dreg = res_reg;
3609         ins->sreg1 = val_reg;
3610         MONO_ADD_INS (cfg->cbb, ins);
3611         res = ins;
3612         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3613
3614         /* Slowpath */
3615         MONO_START_BB (cfg, is_null_bb);
3616         args [0] = rgctx;
3617         EMIT_NEW_ICONST (cfg, args [1], index);
3618         if (mrgctx)
3619                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3620         else
3621                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3622         MONO_INST_NEW (cfg, ins, OP_MOVE);
3623         ins->dreg = res_reg;
3624         ins->sreg1 = call->dreg;
3625         MONO_ADD_INS (cfg->cbb, ins);
3626         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3627
3628         MONO_START_BB (cfg, end_bb);
3629
3630         return res;
3631 #endif
3632 }
3633
3634 /*
3635  * emit_rgctx_fetch:
3636  *
3637  *   Emit IR to load the value of the rgctx entry ENTRY from the rgctx
3638  * given by RGCTX.
3639  */
3640 static inline MonoInst*
3641 emit_rgctx_fetch (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3642 {
3643         if (cfg->llvm_only)
3644                 return emit_rgctx_fetch_inline (cfg, rgctx, entry);
3645         else
3646                 return mono_emit_abs_call (cfg, MONO_PATCH_INFO_RGCTX_FETCH, entry, helper_sig_rgctx_lazy_fetch_trampoline, &rgctx);
3647 }
3648
3649 static MonoInst*
3650 emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
3651                                           MonoClass *klass, MonoRgctxInfoType rgctx_type)
3652 {
3653         MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_CLASS, klass, rgctx_type);
3654         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3655
3656         return emit_rgctx_fetch (cfg, rgctx, entry);
3657 }
3658
3659 static MonoInst*
3660 emit_get_rgctx_sig (MonoCompile *cfg, int context_used,
3661                                         MonoMethodSignature *sig, MonoRgctxInfoType rgctx_type)
3662 {
3663         MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_SIGNATURE, sig, rgctx_type);
3664         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3665
3666         return emit_rgctx_fetch (cfg, rgctx, entry);
3667 }
3668
3669 static MonoInst*
3670 emit_get_rgctx_gsharedvt_call (MonoCompile *cfg, int context_used,
3671                                                            MonoMethodSignature *sig, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3672 {
3673         MonoJumpInfoGSharedVtCall *call_info;
3674         MonoJumpInfoRgctxEntry *entry;
3675         MonoInst *rgctx;
3676
3677         call_info = (MonoJumpInfoGSharedVtCall *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoGSharedVtCall));
3678         call_info->sig = sig;
3679         call_info->method = cmethod;
3680
3681         entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_GSHAREDVT_CALL, call_info, rgctx_type);
3682         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3683
3684         return emit_rgctx_fetch (cfg, rgctx, entry);
3685 }
3686
3687 /*
3688  * emit_get_rgctx_virt_method:
3689  *
3690  *   Return data for method VIRT_METHOD for a receiver of type KLASS.
3691  */
3692 static MonoInst*
3693 emit_get_rgctx_virt_method (MonoCompile *cfg, int context_used,
3694                                                         MonoClass *klass, MonoMethod *virt_method, MonoRgctxInfoType rgctx_type)
3695 {
3696         MonoJumpInfoVirtMethod *info;
3697         MonoJumpInfoRgctxEntry *entry;
3698         MonoInst *rgctx;
3699
3700         info = (MonoJumpInfoVirtMethod *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoVirtMethod));
3701         info->klass = klass;
3702         info->method = virt_method;
3703
3704         entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_VIRT_METHOD, info, rgctx_type);
3705         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3706
3707         return emit_rgctx_fetch (cfg, rgctx, entry);
3708 }
3709
3710 static MonoInst*
3711 emit_get_rgctx_gsharedvt_method (MonoCompile *cfg, int context_used,
3712                                                                  MonoMethod *cmethod, MonoGSharedVtMethodInfo *info)
3713 {
3714         MonoJumpInfoRgctxEntry *entry;
3715         MonoInst *rgctx;
3716
3717         entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_GSHAREDVT_METHOD, info, MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO);
3718         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3719
3720         return emit_rgctx_fetch (cfg, rgctx, entry);
3721 }
3722
3723 /*
3724  * emit_get_rgctx_method:
3725  *
3726  *   Emit IR to load the property RGCTX_TYPE of CMETHOD. If context_used is 0, emit
3727  * normal constants, else emit a load from the rgctx.
3728  */
3729 static MonoInst*
3730 emit_get_rgctx_method (MonoCompile *cfg, int context_used,
3731                                            MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3732 {
3733         if (!context_used) {
3734                 MonoInst *ins;
3735
3736                 switch (rgctx_type) {
3737                 case MONO_RGCTX_INFO_METHOD:
3738                         EMIT_NEW_METHODCONST (cfg, ins, cmethod);
3739                         return ins;
3740                 case MONO_RGCTX_INFO_METHOD_RGCTX:
3741                         EMIT_NEW_METHOD_RGCTX_CONST (cfg, ins, cmethod);
3742                         return ins;
3743                 default:
3744                         g_assert_not_reached ();
3745                 }
3746         } else {
3747                 MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_METHODCONST, cmethod, rgctx_type);
3748                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3749
3750                 return emit_rgctx_fetch (cfg, rgctx, entry);
3751         }
3752 }
3753
3754 static MonoInst*
3755 emit_get_rgctx_field (MonoCompile *cfg, int context_used,
3756                                           MonoClassField *field, MonoRgctxInfoType rgctx_type)
3757 {
3758         MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_FIELD, field, rgctx_type);
3759         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3760
3761         return emit_rgctx_fetch (cfg, rgctx, entry);
3762 }
3763
3764 static int
3765 get_gsharedvt_info_slot (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3766 {
3767         MonoGSharedVtMethodInfo *info = cfg->gsharedvt_info;
3768         MonoRuntimeGenericContextInfoTemplate *template_;
3769         int i, idx;
3770
3771         g_assert (info);
3772
3773         for (i = 0; i < info->num_entries; ++i) {
3774                 MonoRuntimeGenericContextInfoTemplate *otemplate = &info->entries [i];
3775
3776                 if (otemplate->info_type == rgctx_type && otemplate->data == data && rgctx_type != MONO_RGCTX_INFO_LOCAL_OFFSET)
3777                         return i;
3778         }
3779
3780         if (info->num_entries == info->count_entries) {
3781                 MonoRuntimeGenericContextInfoTemplate *new_entries;
3782                 int new_count_entries = info->count_entries ? info->count_entries * 2 : 16;
3783
3784                 new_entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * new_count_entries);
3785
3786                 memcpy (new_entries, info->entries, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
3787                 info->entries = new_entries;
3788                 info->count_entries = new_count_entries;
3789         }
3790
3791         idx = info->num_entries;
3792         template_ = &info->entries [idx];
3793         template_->info_type = rgctx_type;
3794         template_->data = data;
3795
3796         info->num_entries ++;
3797
3798         return idx;
3799 }
3800
3801 /*
3802  * emit_get_gsharedvt_info:
3803  *
3804  *   This is similar to emit_get_rgctx_.., but loads the data from the gsharedvt info var instead of calling an rgctx fetch trampoline.
3805  */
3806 static MonoInst*
3807 emit_get_gsharedvt_info (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3808 {
3809         MonoInst *ins;
3810         int idx, dreg;
3811
3812         idx = get_gsharedvt_info_slot (cfg, data, rgctx_type);
3813         /* Load info->entries [idx] */
3814         dreg = alloc_preg (cfg);
3815         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, cfg->gsharedvt_info_var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
3816
3817         return ins;
3818 }
3819
3820 static MonoInst*
3821 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type)
3822 {
3823         return emit_get_gsharedvt_info (cfg, &klass->byval_arg, rgctx_type);
3824 }
3825
3826 /*
3827  * On return the caller must check @klass for load errors.
3828  */
3829 static void
3830 emit_class_init (MonoCompile *cfg, MonoClass *klass)
3831 {
3832         MonoInst *vtable_arg;
3833         int context_used;
3834
3835         context_used = mini_class_check_context_used (cfg, klass);
3836
3837         if (context_used) {
3838                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
3839                                                                                    klass, MONO_RGCTX_INFO_VTABLE);
3840         } else {
3841                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3842
3843                 if (!vtable)
3844                         return;
3845                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
3846         }
3847
3848         if (!COMPILE_LLVM (cfg) && cfg->backend->have_op_generic_class_init) {
3849                 MonoInst *ins;
3850
3851                 /*
3852                  * Using an opcode instead of emitting IR here allows the hiding of the call inside the opcode,
3853                  * so this doesn't have to clobber any regs and it doesn't break basic blocks.
3854                  */
3855                 MONO_INST_NEW (cfg, ins, OP_GENERIC_CLASS_INIT);
3856                 ins->sreg1 = vtable_arg->dreg;
3857                 MONO_ADD_INS (cfg->cbb, ins);
3858         } else {
3859                 static int byte_offset = -1;
3860                 static guint8 bitmask;
3861                 int bits_reg, inited_reg;
3862                 MonoBasicBlock *inited_bb;
3863                 MonoInst *args [16];
3864
3865                 if (byte_offset < 0)
3866                         mono_marshal_find_bitfield_offset (MonoVTable, initialized, &byte_offset, &bitmask);
3867
3868                 bits_reg = alloc_ireg (cfg);
3869                 inited_reg = alloc_ireg (cfg);
3870
3871                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, bits_reg, vtable_arg->dreg, byte_offset);
3872                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, inited_reg, bits_reg, bitmask);
3873
3874                 NEW_BBLOCK (cfg, inited_bb);
3875
3876                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, inited_reg, 0);
3877                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, inited_bb);
3878
3879                 args [0] = vtable_arg;
3880                 mono_emit_jit_icall (cfg, mono_generic_class_init, args);
3881
3882                 MONO_START_BB (cfg, inited_bb);
3883         }
3884 }
3885
3886 static void
3887 emit_seq_point (MonoCompile *cfg, MonoMethod *method, guint8* ip, gboolean intr_loc, gboolean nonempty_stack)
3888 {
3889         MonoInst *ins;
3890
3891         if (cfg->gen_seq_points && cfg->method == method) {
3892                 NEW_SEQ_POINT (cfg, ins, ip - cfg->header->code, intr_loc);
3893                 if (nonempty_stack)
3894                         ins->flags |= MONO_INST_NONEMPTY_STACK;
3895                 MONO_ADD_INS (cfg->cbb, ins);
3896         }
3897 }
3898
3899 static void
3900 save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean null_check)
3901 {
3902         if (mini_get_debug_options ()->better_cast_details) {
3903                 int vtable_reg = alloc_preg (cfg);
3904                 int klass_reg = alloc_preg (cfg);
3905                 MonoBasicBlock *is_null_bb = NULL;
3906                 MonoInst *tls_get;
3907                 int to_klass_reg, context_used;
3908
3909                 if (null_check) {
3910                         NEW_BBLOCK (cfg, is_null_bb);
3911
3912                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3913                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3914                 }
3915
3916                 tls_get = mono_get_jit_tls_intrinsic (cfg);
3917                 if (!tls_get) {
3918                         fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
3919                         exit (1);
3920                 }
3921
3922                 MONO_ADD_INS (cfg->cbb, tls_get);
3923                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3924                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3925
3926                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
3927
3928                 context_used = mini_class_check_context_used (cfg, klass);
3929                 if (context_used) {
3930                         MonoInst *class_ins;
3931
3932                         class_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3933                         to_klass_reg = class_ins->dreg;
3934                 } else {
3935                         to_klass_reg = alloc_preg (cfg);
3936                         MONO_EMIT_NEW_CLASSCONST (cfg, to_klass_reg, klass);
3937                 }
3938                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
3939
3940                 if (null_check)
3941                         MONO_START_BB (cfg, is_null_bb);
3942         }
3943 }
3944
3945 static void
3946 reset_cast_details (MonoCompile *cfg)
3947 {
3948         /* Reset the variables holding the cast details */
3949         if (mini_get_debug_options ()->better_cast_details) {
3950                 MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
3951
3952                 MONO_ADD_INS (cfg->cbb, tls_get);
3953                 /* It is enough to reset the from field */
3954                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
3955         }
3956 }
3957
3958 /*
3959  * On return the caller must check @array_class for load errors
3960  */
3961 static void
3962 mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_class)
3963 {
3964         int vtable_reg = alloc_preg (cfg);
3965         int context_used;
3966
3967         context_used = mini_class_check_context_used (cfg, array_class);
3968
3969         save_cast_details (cfg, array_class, obj->dreg, FALSE);
3970
3971         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3972
3973         if (cfg->opt & MONO_OPT_SHARED) {
3974                 int class_reg = alloc_preg (cfg);
3975                 MonoInst *ins;
3976
3977                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, class_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3978                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, array_class);
3979                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, class_reg, ins->dreg);
3980         } else if (context_used) {
3981                 MonoInst *vtable_ins;
3982
3983                 vtable_ins = emit_get_rgctx_klass (cfg, context_used, array_class, MONO_RGCTX_INFO_VTABLE);
3984                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vtable_ins->dreg);
3985         } else {
3986                 if (cfg->compile_aot) {
3987                         int vt_reg;
3988                         MonoVTable *vtable;
3989
3990                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3991                                 return;
3992                         vt_reg = alloc_preg (cfg);
3993                         MONO_EMIT_NEW_VTABLECONST (cfg, vt_reg, vtable);
3994                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vt_reg);
3995                 } else {
3996                         MonoVTable *vtable;
3997                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3998                                 return;
3999                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vtable);
4000                 }
4001         }
4002         
4003         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
4004
4005         reset_cast_details (cfg);
4006 }
4007
4008 /**
4009  * Handles unbox of a Nullable<T>. If context_used is non zero, then shared 
4010  * generic code is generated.
4011  */
4012 static MonoInst*
4013 handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int context_used)
4014 {
4015         MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
4016
4017         if (context_used) {
4018                 MonoInst *rgctx, *addr;
4019
4020                 /* FIXME: What if the class is shared?  We might not
4021                    have to get the address of the method from the
4022                    RGCTX. */
4023                 addr = emit_get_rgctx_method (cfg, context_used, method,
4024                                                                           MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4025                 if (cfg->llvm_only && cfg->gsharedvt) {
4026                         return emit_llvmonly_calli (cfg, mono_method_signature (method), &val, addr);
4027                 } else {
4028                         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
4029
4030                         return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
4031                 }
4032         } else {
4033                 gboolean pass_vtable, pass_mrgctx;
4034                 MonoInst *rgctx_arg = NULL;
4035
4036                 check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
4037                 g_assert (!pass_mrgctx);
4038
4039                 if (pass_vtable) {
4040                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4041
4042                         g_assert (vtable);
4043                         EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4044                 }
4045
4046                 return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4047         }
4048 }
4049
4050 static MonoInst*
4051 handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_used)
4052 {
4053         MonoInst *add;
4054         int obj_reg;
4055         int vtable_reg = alloc_dreg (cfg ,STACK_PTR);
4056         int klass_reg = alloc_dreg (cfg ,STACK_PTR);
4057         int eclass_reg = alloc_dreg (cfg ,STACK_PTR);
4058         int rank_reg = alloc_dreg (cfg ,STACK_I4);
4059
4060         obj_reg = sp [0]->dreg;
4061         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4062         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
4063
4064         /* FIXME: generics */
4065         g_assert (klass->rank == 0);
4066                         
4067         // Check rank == 0
4068         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 0);
4069         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4070
4071         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4072         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, element_class));
4073
4074         if (context_used) {
4075                 MonoInst *element_class;
4076
4077                 /* This assertion is from the unboxcast insn */
4078                 g_assert (klass->rank == 0);
4079
4080                 element_class = emit_get_rgctx_klass (cfg, context_used,
4081                                 klass, MONO_RGCTX_INFO_ELEMENT_KLASS);
4082
4083                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, eclass_reg, element_class->dreg);
4084                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4085         } else {
4086                 save_cast_details (cfg, klass->element_class, obj_reg, FALSE);
4087                 mini_emit_class_check (cfg, eclass_reg, klass->element_class);
4088                 reset_cast_details (cfg);
4089         }
4090
4091         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), obj_reg, sizeof (MonoObject));
4092         MONO_ADD_INS (cfg->cbb, add);
4093         add->type = STACK_MP;
4094         add->klass = klass;
4095
4096         return add;
4097 }
4098
4099 static MonoInst*
4100 handle_unbox_gsharedvt (MonoCompile *cfg, MonoClass *klass, MonoInst *obj)
4101 {
4102         MonoInst *addr, *klass_inst, *is_ref, *args[16];
4103         MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4104         MonoInst *ins;
4105         int dreg, addr_reg;
4106
4107         klass_inst = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_KLASS);
4108
4109         /* obj */
4110         args [0] = obj;
4111
4112         /* klass */
4113         args [1] = klass_inst;
4114
4115         /* CASTCLASS */
4116         obj = mono_emit_jit_icall (cfg, mono_object_castclass_unbox, args);
4117
4118         NEW_BBLOCK (cfg, is_ref_bb);
4119         NEW_BBLOCK (cfg, is_nullable_bb);
4120         NEW_BBLOCK (cfg, end_bb);
4121         is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4122         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
4123         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4124
4125         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
4126         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4127
4128         /* This will contain either the address of the unboxed vtype, or an address of the temporary where the ref is stored */
4129         addr_reg = alloc_dreg (cfg, STACK_MP);
4130
4131         /* Non-ref case */
4132         /* UNBOX */
4133         NEW_BIALU_IMM (cfg, addr, OP_ADD_IMM, addr_reg, obj->dreg, sizeof (MonoObject));
4134         MONO_ADD_INS (cfg->cbb, addr);
4135
4136         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4137
4138         /* Ref case */
4139         MONO_START_BB (cfg, is_ref_bb);
4140
4141         /* Save the ref to a temporary */
4142         dreg = alloc_ireg (cfg);
4143         EMIT_NEW_VARLOADA_VREG (cfg, addr, dreg, &klass->byval_arg);
4144         addr->dreg = addr_reg;
4145         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, obj->dreg);
4146         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4147
4148         /* Nullable case */
4149         MONO_START_BB (cfg, is_nullable_bb);
4150
4151         {
4152                 MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX);
4153                 MonoInst *unbox_call;
4154                 MonoMethodSignature *unbox_sig;
4155
4156                 unbox_sig = (MonoMethodSignature *)mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4157                 unbox_sig->ret = &klass->byval_arg;
4158                 unbox_sig->param_count = 1;
4159                 unbox_sig->params [0] = &mono_defaults.object_class->byval_arg;
4160
4161                 if (cfg->llvm_only)
4162                         unbox_call = emit_llvmonly_calli (cfg, unbox_sig, &obj, addr);
4163                 else
4164                         unbox_call = mono_emit_calli (cfg, unbox_sig, &obj, addr, NULL, NULL);
4165
4166                 EMIT_NEW_VARLOADA_VREG (cfg, addr, unbox_call->dreg, &klass->byval_arg);
4167                 addr->dreg = addr_reg;
4168         }
4169
4170         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4171
4172         /* End */
4173         MONO_START_BB (cfg, end_bb);
4174
4175         /* LDOBJ */
4176         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr_reg, 0);
4177
4178         return ins;
4179 }
4180
4181 /*
4182  * Returns NULL and set the cfg exception on error.
4183  */
4184 static MonoInst*
4185 handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_used)
4186 {
4187         MonoInst *iargs [2];
4188         void *alloc_ftn;
4189
4190         if (context_used) {
4191                 MonoInst *data;
4192                 MonoRgctxInfoType rgctx_info;
4193                 MonoInst *iargs [2];
4194                 gboolean known_instance_size = !mini_is_gsharedvt_klass (klass);
4195
4196                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (klass, for_box, known_instance_size);
4197
4198                 if (cfg->opt & MONO_OPT_SHARED)
4199                         rgctx_info = MONO_RGCTX_INFO_KLASS;
4200                 else
4201                         rgctx_info = MONO_RGCTX_INFO_VTABLE;
4202                 data = emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
4203
4204                 if (cfg->opt & MONO_OPT_SHARED) {
4205                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4206                         iargs [1] = data;
4207                         alloc_ftn = ves_icall_object_new;
4208                 } else {
4209                         iargs [0] = data;
4210                         alloc_ftn = ves_icall_object_new_specific;
4211                 }
4212
4213                 if (managed_alloc && !(cfg->opt & MONO_OPT_SHARED)) {
4214                         if (known_instance_size) {
4215                                 int size = mono_class_instance_size (klass);
4216                                 if (size < sizeof (MonoObject))
4217                                         g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4218
4219                                 EMIT_NEW_ICONST (cfg, iargs [1], mono_gc_get_aligned_size_for_allocator (size));
4220                         }
4221                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4222                 }
4223
4224                 return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4225         }
4226
4227         if (cfg->opt & MONO_OPT_SHARED) {
4228                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4229                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
4230
4231                 alloc_ftn = ves_icall_object_new;
4232         } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !klass->generic_class) {
4233                 /* This happens often in argument checking code, eg. throw new FooException... */
4234                 /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
4235                 EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
4236                 return mono_emit_jit_icall (cfg, mono_helper_newobj_mscorlib, iargs);
4237         } else {
4238                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
4239                 MonoMethod *managed_alloc = NULL;
4240                 gboolean pass_lw;
4241
4242                 if (!vtable) {
4243                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4244                         cfg->exception_ptr = klass;
4245                         return NULL;
4246                 }
4247
4248                 managed_alloc = mono_gc_get_managed_allocator (klass, for_box, TRUE);
4249
4250                 if (managed_alloc) {
4251                         int size = mono_class_instance_size (klass);
4252                         if (size < sizeof (MonoObject))
4253                                 g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4254
4255                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4256                         EMIT_NEW_ICONST (cfg, iargs [1], mono_gc_get_aligned_size_for_allocator (size));
4257                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4258                 }
4259                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
4260                 if (pass_lw) {
4261                         guint32 lw = vtable->klass->instance_size;
4262                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
4263                         EMIT_NEW_ICONST (cfg, iargs [0], lw);
4264                         EMIT_NEW_VTABLECONST (cfg, iargs [1], vtable);
4265                 }
4266                 else {
4267                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4268                 }
4269         }
4270
4271         return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4272 }
4273         
4274 /*
4275  * Returns NULL and set the cfg exception on error.
4276  */     
4277 static MonoInst*
4278 handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used)
4279 {
4280         MonoInst *alloc, *ins;
4281
4282         if (mono_class_is_nullable (klass)) {
4283                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
4284
4285                 if (context_used) {
4286                         if (cfg->llvm_only && cfg->gsharedvt) {
4287                                 MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4288                                                                                                                 MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4289                                 return emit_llvmonly_calli (cfg, mono_method_signature (method), &val, addr);
4290                         } else {
4291                                 /* FIXME: What if the class is shared?  We might not
4292                                    have to get the method address from the RGCTX. */
4293                                 MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4294                                                                                                                 MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4295                                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
4296
4297                                 return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
4298                         }
4299                 } else {
4300                         gboolean pass_vtable, pass_mrgctx;
4301                         MonoInst *rgctx_arg = NULL;
4302
4303                         check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
4304                         g_assert (!pass_mrgctx);
4305
4306                         if (pass_vtable) {
4307                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4308
4309                                 g_assert (vtable);
4310                                 EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4311                         }
4312
4313                         return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4314                 }
4315         }
4316
4317         if (mini_is_gsharedvt_klass (klass)) {
4318                 MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4319                 MonoInst *res, *is_ref, *src_var, *addr;
4320                 int dreg;
4321
4322                 dreg = alloc_ireg (cfg);
4323
4324                 NEW_BBLOCK (cfg, is_ref_bb);
4325                 NEW_BBLOCK (cfg, is_nullable_bb);
4326                 NEW_BBLOCK (cfg, end_bb);
4327                 is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4328                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
4329                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4330
4331                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
4332                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4333
4334                 /* Non-ref case */
4335                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4336                 if (!alloc)
4337                         return NULL;
4338                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4339                 ins->opcode = OP_STOREV_MEMBASE;
4340
4341                 EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, alloc->dreg);
4342                 res->type = STACK_OBJ;
4343                 res->klass = klass;
4344                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4345                 
4346                 /* Ref case */
4347                 MONO_START_BB (cfg, is_ref_bb);
4348
4349                 /* val is a vtype, so has to load the value manually */
4350                 src_var = get_vreg_to_inst (cfg, val->dreg);
4351                 if (!src_var)
4352                         src_var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, val->dreg);
4353                 EMIT_NEW_VARLOADA (cfg, addr, src_var, src_var->inst_vtype);
4354                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, addr->dreg, 0);
4355                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4356
4357                 /* Nullable case */
4358                 MONO_START_BB (cfg, is_nullable_bb);
4359
4360                 {
4361                         MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass,
4362                                                                                                         MONO_RGCTX_INFO_NULLABLE_CLASS_BOX);
4363                         MonoInst *box_call;
4364                         MonoMethodSignature *box_sig;
4365
4366                         /*
4367                          * klass is Nullable<T>, need to call Nullable<T>.Box () using a gsharedvt signature, but we cannot
4368                          * construct that method at JIT time, so have to do things by hand.
4369                          */
4370                         box_sig = (MonoMethodSignature *)mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4371                         box_sig->ret = &mono_defaults.object_class->byval_arg;
4372                         box_sig->param_count = 1;
4373                         box_sig->params [0] = &klass->byval_arg;
4374
4375                         if (cfg->llvm_only)
4376                                 box_call = emit_llvmonly_calli (cfg, box_sig, &val, addr);
4377                         else
4378                                 box_call = mono_emit_calli (cfg, box_sig, &val, addr, NULL, NULL);
4379                         EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, box_call->dreg);
4380                         res->type = STACK_OBJ;
4381                         res->klass = klass;
4382                 }
4383
4384                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4385
4386                 MONO_START_BB (cfg, end_bb);
4387
4388                 return res;
4389         } else {
4390                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4391                 if (!alloc)
4392                         return NULL;
4393
4394                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4395                 return alloc;
4396         }
4397 }
4398
4399 static gboolean
4400 mini_class_has_reference_variant_generic_argument (MonoCompile *cfg, MonoClass *klass, int context_used)
4401 {
4402         int i;
4403         MonoGenericContainer *container;
4404         MonoGenericInst *ginst;
4405
4406         if (klass->generic_class) {
4407                 container = klass->generic_class->container_class->generic_container;
4408                 ginst = klass->generic_class->context.class_inst;
4409         } else if (klass->generic_container && context_used) {
4410                 container = klass->generic_container;
4411                 ginst = container->context.class_inst;
4412         } else {
4413                 return FALSE;
4414         }
4415
4416         for (i = 0; i < container->type_argc; ++i) {
4417                 MonoType *type;
4418                 if (!(mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT)))
4419                         continue;
4420                 type = ginst->type_argv [i];
4421                 if (mini_type_is_reference (type))
4422                         return TRUE;
4423         }
4424         return FALSE;
4425 }
4426
4427 static GHashTable* direct_icall_type_hash;
4428
4429 static gboolean
4430 icall_is_direct_callable (MonoCompile *cfg, MonoMethod *cmethod)
4431 {
4432         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
4433         if (!direct_icalls_enabled (cfg))
4434                 return FALSE;
4435
4436         /*
4437          * An icall is directly callable if it doesn't directly or indirectly call mono_raise_exception ().
4438          * Whitelist a few icalls for now.
4439          */
4440         if (!direct_icall_type_hash) {
4441                 GHashTable *h = g_hash_table_new (g_str_hash, g_str_equal);
4442
4443                 g_hash_table_insert (h, (char*)"Decimal", GUINT_TO_POINTER (1));
4444                 g_hash_table_insert (h, (char*)"Number", GUINT_TO_POINTER (1));
4445                 g_hash_table_insert (h, (char*)"Buffer", GUINT_TO_POINTER (1));
4446                 g_hash_table_insert (h, (char*)"Monitor", GUINT_TO_POINTER (1));
4447                 mono_memory_barrier ();
4448                 direct_icall_type_hash = h;
4449         }
4450
4451         if (cmethod->klass == mono_defaults.math_class)
4452                 return TRUE;
4453         /* No locking needed */
4454         if (cmethod->klass->image == mono_defaults.corlib && g_hash_table_lookup (direct_icall_type_hash, cmethod->klass->name))
4455                 return TRUE;
4456         return FALSE;
4457 }
4458
4459 #define is_complex_isinst(klass) ((klass->flags & TYPE_ATTRIBUTE_INTERFACE) || klass->rank || mono_class_is_nullable (klass) || mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_SEALED) || klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR)
4460
4461 static MonoInst*
4462 emit_castclass_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args)
4463 {
4464         MonoMethod *mono_castclass;
4465         MonoInst *res;
4466
4467         mono_castclass = mono_marshal_get_castclass_with_cache ();
4468
4469         save_cast_details (cfg, klass, args [0]->dreg, TRUE);
4470         res = mono_emit_method_call (cfg, mono_castclass, args, NULL);
4471         reset_cast_details (cfg);
4472
4473         return res;
4474 }
4475
4476 static int
4477 get_castclass_cache_idx (MonoCompile *cfg)
4478 {
4479         /* Each CASTCLASS_CACHE patch needs a unique index which identifies the call site */
4480         cfg->castclass_cache_index ++;
4481         return (cfg->method_index << 16) | cfg->castclass_cache_index;
4482 }
4483
4484 static MonoInst*
4485 emit_castclass_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass)
4486 {
4487         MonoInst *args [3];
4488         int idx;
4489
4490         /* obj */
4491         args [0] = obj;
4492
4493         /* klass */
4494         EMIT_NEW_CLASSCONST (cfg, args [1], klass);
4495
4496         /* inline cache*/
4497         idx = get_castclass_cache_idx (cfg);
4498         args [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
4499
4500         /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
4501         return emit_castclass_with_cache (cfg, klass, args);
4502 }
4503
4504 /*
4505  * Returns NULL and set the cfg exception on error.
4506  */
4507 static MonoInst*
4508 handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, guint8 *ip, int *inline_costs)
4509 {
4510         MonoBasicBlock *is_null_bb;
4511         int obj_reg = src->dreg;
4512         int vtable_reg = alloc_preg (cfg);
4513         int context_used;
4514         MonoInst *klass_inst = NULL, *res;
4515
4516         context_used = mini_class_check_context_used (cfg, klass);
4517
4518         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
4519                 res = emit_castclass_with_cache_nonshared (cfg, src, klass);
4520                 (*inline_costs) += 2;
4521                 return res;
4522         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
4523                 MonoMethod *mono_castclass;
4524                 MonoInst *iargs [1];
4525                 int costs;
4526
4527                 mono_castclass = mono_marshal_get_castclass (klass); 
4528                 iargs [0] = src;
4529                                 
4530                 save_cast_details (cfg, klass, src->dreg, TRUE);
4531                 costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
4532                                                            iargs, ip, cfg->real_offset, TRUE);
4533                 reset_cast_details (cfg);
4534                 CHECK_CFG_EXCEPTION;
4535                 g_assert (costs > 0);
4536                                 
4537                 cfg->real_offset += 5;
4538
4539                 (*inline_costs) += costs;
4540
4541                 return src;
4542         }
4543
4544         if (context_used) {
4545                 MonoInst *args [3];
4546
4547                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4548                         MonoInst *cache_ins;
4549
4550                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4551
4552                         /* obj */
4553                         args [0] = src;
4554
4555                         /* klass - it's the second element of the cache entry*/
4556                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4557
4558                         /* cache */
4559                         args [2] = cache_ins;
4560
4561                         return emit_castclass_with_cache (cfg, klass, args);
4562                 }
4563
4564                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4565         }
4566
4567         NEW_BBLOCK (cfg, is_null_bb);
4568
4569         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4570         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
4571
4572         save_cast_details (cfg, klass, obj_reg, FALSE);
4573
4574         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4575                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4576                 mini_emit_iface_cast (cfg, vtable_reg, klass, NULL, NULL);
4577         } else {
4578                 int klass_reg = alloc_preg (cfg);
4579
4580                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4581
4582                 if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4583                         /* the remoting code is broken, access the class for now */
4584                         if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4585                                 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4586                                 if (!vt) {
4587                                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4588                                         cfg->exception_ptr = klass;
4589                                         return NULL;
4590                                 }
4591                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4592                         } else {
4593                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4594                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4595                         }
4596                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4597                 } else {
4598                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4599                         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
4600                 }
4601         }
4602
4603         MONO_START_BB (cfg, is_null_bb);
4604
4605         reset_cast_details (cfg);
4606
4607         return src;
4608
4609 exception_exit:
4610         return NULL;
4611 }
4612
4613 /*
4614  * Returns NULL and set the cfg exception on error.
4615  */
4616 static MonoInst*
4617 handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
4618 {
4619         MonoInst *ins;
4620         MonoBasicBlock *is_null_bb, *false_bb, *end_bb;
4621         int obj_reg = src->dreg;
4622         int vtable_reg = alloc_preg (cfg);
4623         int res_reg = alloc_ireg_ref (cfg);
4624         MonoInst *klass_inst = NULL;
4625
4626         if (context_used) {
4627                 MonoInst *args [3];
4628
4629                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4630                         MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
4631                         MonoInst *cache_ins;
4632
4633                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4634
4635                         /* obj */
4636                         args [0] = src;
4637
4638                         /* klass - it's the second element of the cache entry*/
4639                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4640
4641                         /* cache */
4642                         args [2] = cache_ins;
4643
4644                         return mono_emit_method_call (cfg, mono_isinst, args, NULL);
4645                 }
4646
4647                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4648         }
4649
4650         NEW_BBLOCK (cfg, is_null_bb);
4651         NEW_BBLOCK (cfg, false_bb);
4652         NEW_BBLOCK (cfg, end_bb);
4653
4654         /* Do the assignment at the beginning, so the other assignment can be if converted */
4655         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, res_reg, obj_reg);
4656         ins->type = STACK_OBJ;
4657         ins->klass = klass;
4658
4659         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4660         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_null_bb);
4661
4662         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4663
4664         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4665                 g_assert (!context_used);
4666                 /* the is_null_bb target simply copies the input register to the output */
4667                 mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb);
4668         } else {
4669                 int klass_reg = alloc_preg (cfg);
4670
4671                 if (klass->rank) {
4672                         int rank_reg = alloc_preg (cfg);
4673                         int eclass_reg = alloc_preg (cfg);
4674
4675                         g_assert (!context_used);
4676                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
4677                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
4678                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4679                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4680                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
4681                         if (klass->cast_class == mono_defaults.object_class) {
4682                                 int parent_reg = alloc_preg (cfg);
4683                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
4684                                 mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, is_null_bb);
4685                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4686                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4687                         } else if (klass->cast_class == mono_defaults.enum_class->parent) {
4688                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, is_null_bb);
4689                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);                          
4690                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4691                         } else if (klass->cast_class == mono_defaults.enum_class) {
4692                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4693                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4694                         } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
4695                                 mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4696                         } else {
4697                                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) {
4698                                         /* Check that the object is a vector too */
4699                                         int bounds_reg = alloc_preg (cfg);
4700                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
4701                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
4702                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4703                                 }
4704
4705                                 /* the is_null_bb target simply copies the input register to the output */
4706                                 mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4707                         }
4708                 } else if (mono_class_is_nullable (klass)) {
4709                         g_assert (!context_used);
4710                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4711                         /* the is_null_bb target simply copies the input register to the output */
4712                         mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
4713                 } else {
4714                         if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4715                                 g_assert (!context_used);
4716                                 /* the remoting code is broken, access the class for now */
4717                                 if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4718                                         MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4719                                         if (!vt) {
4720                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4721                                                 cfg->exception_ptr = klass;
4722                                                 return NULL;
4723                                         }
4724                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4725                                 } else {
4726                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4727                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4728                                 }
4729                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4730                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
4731                         } else {
4732                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4733                                 /* the is_null_bb target simply copies the input register to the output */
4734                                 mini_emit_isninst_cast_inst (cfg, klass_reg, klass, klass_inst, false_bb, is_null_bb);
4735                         }
4736                 }
4737         }
4738
4739         MONO_START_BB (cfg, false_bb);
4740
4741         MONO_EMIT_NEW_PCONST (cfg, res_reg, 0);
4742         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4743
4744         MONO_START_BB (cfg, is_null_bb);
4745
4746         MONO_START_BB (cfg, end_bb);
4747
4748         return ins;
4749 }
4750
4751 static MonoInst*
4752 handle_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4753 {
4754         /* This opcode takes as input an object reference and a class, and returns:
4755         0) if the object is an instance of the class,
4756         1) if the object is not instance of the class,
4757         2) if the object is a proxy whose type cannot be determined */
4758
4759         MonoInst *ins;
4760 #ifndef DISABLE_REMOTING
4761         MonoBasicBlock *true_bb, *false_bb, *false2_bb, *end_bb, *no_proxy_bb, *interface_fail_bb;
4762 #else
4763         MonoBasicBlock *true_bb, *false_bb, *end_bb;
4764 #endif
4765         int obj_reg = src->dreg;
4766         int dreg = alloc_ireg (cfg);
4767         int tmp_reg;
4768 #ifndef DISABLE_REMOTING
4769         int klass_reg = alloc_preg (cfg);
4770 #endif
4771
4772         NEW_BBLOCK (cfg, true_bb);
4773         NEW_BBLOCK (cfg, false_bb);
4774         NEW_BBLOCK (cfg, end_bb);
4775 #ifndef DISABLE_REMOTING
4776         NEW_BBLOCK (cfg, false2_bb);
4777         NEW_BBLOCK (cfg, no_proxy_bb);
4778 #endif
4779
4780         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4781         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
4782
4783         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4784 #ifndef DISABLE_REMOTING
4785                 NEW_BBLOCK (cfg, interface_fail_bb);
4786 #endif
4787
4788                 tmp_reg = alloc_preg (cfg);
4789                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4790 #ifndef DISABLE_REMOTING
4791                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, true_bb);
4792                 MONO_START_BB (cfg, interface_fail_bb);
4793                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4794                 
4795                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, false_bb);
4796
4797                 tmp_reg = alloc_preg (cfg);
4798                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4799                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4800                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false2_bb);                
4801 #else
4802                 mini_emit_iface_cast (cfg, tmp_reg, klass, false_bb, true_bb);
4803 #endif
4804         } else {
4805 #ifndef DISABLE_REMOTING
4806                 tmp_reg = alloc_preg (cfg);
4807                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4808                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4809
4810                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4811                 tmp_reg = alloc_preg (cfg);
4812                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4813                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4814
4815                 tmp_reg = alloc_preg (cfg);             
4816                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4817                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4818                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4819                 
4820                 mini_emit_isninst_cast (cfg, klass_reg, klass, false2_bb, true_bb);
4821                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false2_bb);
4822
4823                 MONO_START_BB (cfg, no_proxy_bb);
4824
4825                 mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, true_bb);
4826 #else
4827                 g_error ("transparent proxy support is disabled while trying to JIT code that uses it");
4828 #endif
4829         }
4830
4831         MONO_START_BB (cfg, false_bb);
4832
4833         MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4834         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4835
4836 #ifndef DISABLE_REMOTING
4837         MONO_START_BB (cfg, false2_bb);
4838
4839         MONO_EMIT_NEW_ICONST (cfg, dreg, 2);
4840         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4841 #endif
4842
4843         MONO_START_BB (cfg, true_bb);
4844
4845         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4846
4847         MONO_START_BB (cfg, end_bb);
4848
4849         /* FIXME: */
4850         MONO_INST_NEW (cfg, ins, OP_ICONST);
4851         ins->dreg = dreg;
4852         ins->type = STACK_I4;
4853
4854         return ins;
4855 }
4856
4857 static MonoInst*
4858 handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4859 {
4860         /* This opcode takes as input an object reference and a class, and returns:
4861         0) if the object is an instance of the class,
4862         1) if the object is a proxy whose type cannot be determined
4863         an InvalidCastException exception is thrown otherwhise*/
4864         
4865         MonoInst *ins;
4866 #ifndef DISABLE_REMOTING
4867         MonoBasicBlock *end_bb, *ok_result_bb, *no_proxy_bb, *interface_fail_bb, *fail_1_bb;
4868 #else
4869         MonoBasicBlock *ok_result_bb;
4870 #endif
4871         int obj_reg = src->dreg;
4872         int dreg = alloc_ireg (cfg);
4873         int tmp_reg = alloc_preg (cfg);
4874
4875 #ifndef DISABLE_REMOTING
4876         int klass_reg = alloc_preg (cfg);
4877         NEW_BBLOCK (cfg, end_bb);
4878 #endif
4879
4880         NEW_BBLOCK (cfg, ok_result_bb);
4881
4882         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4883         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, ok_result_bb);
4884
4885         save_cast_details (cfg, klass, obj_reg, FALSE);
4886
4887         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4888 #ifndef DISABLE_REMOTING
4889                 NEW_BBLOCK (cfg, interface_fail_bb);
4890         
4891                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4892                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, ok_result_bb);
4893                 MONO_START_BB (cfg, interface_fail_bb);
4894                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4895
4896                 mini_emit_class_check (cfg, klass_reg, mono_defaults.transparent_proxy_class);
4897
4898                 tmp_reg = alloc_preg (cfg);             
4899                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4900                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4901                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
4902                 
4903                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4904                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4905 #else
4906                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4907                 mini_emit_iface_cast (cfg, tmp_reg, klass, NULL, NULL);
4908                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, ok_result_bb);
4909 #endif
4910         } else {
4911 #ifndef DISABLE_REMOTING
4912                 NEW_BBLOCK (cfg, no_proxy_bb);
4913
4914                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4915                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4916                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4917
4918                 tmp_reg = alloc_preg (cfg);
4919                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4920                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4921
4922                 tmp_reg = alloc_preg (cfg);
4923                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4924                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4925                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4926
4927                 NEW_BBLOCK (cfg, fail_1_bb);
4928                 
4929                 mini_emit_isninst_cast (cfg, klass_reg, klass, fail_1_bb, ok_result_bb);
4930
4931                 MONO_START_BB (cfg, fail_1_bb);
4932
4933                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4934                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4935
4936                 MONO_START_BB (cfg, no_proxy_bb);
4937
4938                 mini_emit_castclass (cfg, obj_reg, klass_reg, klass, ok_result_bb);
4939 #else
4940                 g_error ("Transparent proxy support is disabled while trying to JIT code that uses it");
4941 #endif
4942         }
4943
4944         MONO_START_BB (cfg, ok_result_bb);
4945
4946         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4947
4948 #ifndef DISABLE_REMOTING
4949         MONO_START_BB (cfg, end_bb);
4950 #endif
4951
4952         /* FIXME: */
4953         MONO_INST_NEW (cfg, ins, OP_ICONST);
4954         ins->dreg = dreg;
4955         ins->type = STACK_I4;
4956
4957         return ins;
4958 }
4959
4960 static G_GNUC_UNUSED MonoInst*
4961 handle_enum_has_flag (MonoCompile *cfg, MonoClass *klass, MonoInst *enum_this, MonoInst *enum_flag)
4962 {
4963         MonoType *enum_type = mono_type_get_underlying_type (&klass->byval_arg);
4964         guint32 load_opc = mono_type_to_load_membase (cfg, enum_type);
4965         gboolean is_i4;
4966
4967         switch (enum_type->type) {
4968         case MONO_TYPE_I8:
4969         case MONO_TYPE_U8:
4970 #if SIZEOF_REGISTER == 8
4971         case MONO_TYPE_I:
4972         case MONO_TYPE_U:
4973 #endif
4974                 is_i4 = FALSE;
4975                 break;
4976         default:
4977                 is_i4 = TRUE;
4978                 break;
4979         }
4980
4981         {
4982                 MonoInst *load, *and_, *cmp, *ceq;
4983                 int enum_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4984                 int and_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4985                 int dest_reg = alloc_ireg (cfg);
4986
4987                 EMIT_NEW_LOAD_MEMBASE (cfg, load, load_opc, enum_reg, enum_this->dreg, 0);
4988                 EMIT_NEW_BIALU (cfg, and_, is_i4 ? OP_IAND : OP_LAND, and_reg, enum_reg, enum_flag->dreg);
4989                 EMIT_NEW_BIALU (cfg, cmp, is_i4 ? OP_ICOMPARE : OP_LCOMPARE, -1, and_reg, enum_flag->dreg);
4990                 EMIT_NEW_UNALU (cfg, ceq, is_i4 ? OP_ICEQ : OP_LCEQ, dest_reg, -1);
4991
4992                 ceq->type = STACK_I4;
4993
4994                 if (!is_i4) {
4995                         load = mono_decompose_opcode (cfg, load);
4996                         and_ = mono_decompose_opcode (cfg, and_);
4997                         cmp = mono_decompose_opcode (cfg, cmp);
4998                         ceq = mono_decompose_opcode (cfg, ceq);
4999                 }
5000
5001                 return ceq;
5002         }
5003 }
5004
5005 /*
5006  * Returns NULL and set the cfg exception on error.
5007  */
5008 static G_GNUC_UNUSED MonoInst*
5009 handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used, gboolean virtual_)
5010 {
5011         MonoInst *ptr;
5012         int dreg;
5013         gpointer trampoline;
5014         MonoInst *obj, *method_ins, *tramp_ins;
5015         MonoDomain *domain;
5016         guint8 **code_slot;
5017
5018         if (virtual_ && !cfg->llvm_only) {
5019                 MonoMethod *invoke = mono_get_delegate_invoke (klass);
5020                 g_assert (invoke);
5021
5022                 if (!mono_get_delegate_virtual_invoke_impl (mono_method_signature (invoke), context_used ? NULL : method))
5023                         return NULL;
5024         }
5025
5026         obj = handle_alloc (cfg, klass, FALSE, mono_class_check_context_used (klass));
5027         if (!obj)
5028                 return NULL;
5029
5030         /* Inline the contents of mono_delegate_ctor */
5031
5032         /* Set target field */
5033         /* Optimize away setting of NULL target */
5034         if (!(target->opcode == OP_PCONST && target->inst_p0 == 0)) {
5035                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
5036                 if (cfg->gen_write_barriers) {
5037                         dreg = alloc_preg (cfg);
5038                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target));
5039                         emit_write_barrier (cfg, ptr, target);
5040                 }
5041         }
5042
5043         /* Set method field */
5044         method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
5045         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
5046
5047         /* 
5048          * To avoid looking up the compiled code belonging to the target method
5049          * in mono_delegate_trampoline (), we allocate a per-domain memory slot to
5050          * store it, and we fill it after the method has been compiled.
5051          */
5052         if (!method->dynamic && !(cfg->opt & MONO_OPT_SHARED)) {
5053                 MonoInst *code_slot_ins;
5054
5055                 if (context_used) {
5056                         code_slot_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD_DELEGATE_CODE);
5057                 } else {
5058                         domain = mono_domain_get ();
5059                         mono_domain_lock (domain);
5060                         if (!domain_jit_info (domain)->method_code_hash)
5061                                 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
5062                         code_slot = (guint8 **)g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
5063                         if (!code_slot) {
5064                                 code_slot = (guint8 **)mono_domain_alloc0 (domain, sizeof (gpointer));
5065                                 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
5066                         }
5067                         mono_domain_unlock (domain);
5068
5069                         code_slot_ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHOD_CODE_SLOT, method);
5070                 }
5071                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);                
5072         }
5073
5074         if (cfg->llvm_only) {
5075                 MonoInst *args [16];
5076
5077                 if (virtual_) {
5078                         args [0] = obj;
5079                         args [1] = target;
5080                         args [2] = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
5081                         mono_emit_jit_icall (cfg, mono_llvmonly_init_delegate_virtual, args);
5082                 } else {
5083                         args [0] = obj;
5084                         mono_emit_jit_icall (cfg, mono_llvmonly_init_delegate, args);
5085                 }
5086
5087                 return obj;
5088         }
5089
5090         if (cfg->compile_aot) {
5091                 MonoDelegateClassMethodPair *del_tramp;
5092
5093                 del_tramp = (MonoDelegateClassMethodPair *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoDelegateClassMethodPair));
5094                 del_tramp->klass = klass;
5095                 del_tramp->method = context_used ? NULL : method;
5096                 del_tramp->is_virtual = virtual_;
5097                 EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_DELEGATE_TRAMPOLINE, del_tramp);
5098         } else {
5099                 if (virtual_)
5100                         trampoline = mono_create_delegate_virtual_trampoline (cfg->domain, klass, context_used ? NULL : method);
5101                 else
5102                         trampoline = mono_create_delegate_trampoline_info (cfg->domain, klass, context_used ? NULL : method);
5103                 EMIT_NEW_PCONST (cfg, tramp_ins, trampoline);
5104         }
5105
5106         /* Set invoke_impl field */
5107         if (virtual_) {
5108                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), tramp_ins->dreg);
5109         } else {
5110                 dreg = alloc_preg (cfg);
5111                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, invoke_impl));
5112                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), dreg);
5113
5114                 dreg = alloc_preg (cfg);
5115                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, method_ptr));
5116                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), dreg);
5117         }
5118
5119         dreg = alloc_preg (cfg);
5120         MONO_EMIT_NEW_ICONST (cfg, dreg, virtual_ ? 1 : 0);
5121         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_is_virtual), dreg);
5122
5123         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
5124
5125         return obj;
5126 }
5127
5128 static MonoInst*
5129 handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
5130 {
5131         MonoJitICallInfo *info;
5132
5133         /* Need to register the icall so it gets an icall wrapper */
5134         info = mono_get_array_new_va_icall (rank);
5135
5136         cfg->flags |= MONO_CFG_HAS_VARARGS;
5137
5138         /* mono_array_new_va () needs a vararg calling convention */
5139         cfg->exception_message = g_strdup ("array-new");
5140         cfg->disable_llvm = TRUE;
5141
5142         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
5143         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
5144 }
5145
5146 /*
5147  * handle_constrained_gsharedvt_call:
5148  *
5149  *   Handle constrained calls where the receiver is a gsharedvt type.
5150  * Return the instruction representing the call. Set the cfg exception on failure.
5151  */
5152 static MonoInst*
5153 handle_constrained_gsharedvt_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp, MonoClass *constrained_class,
5154                                                                    gboolean *ref_emit_widen)
5155 {
5156         MonoInst *ins = NULL;
5157         gboolean emit_widen = *ref_emit_widen;
5158
5159         /*
5160          * Constrained calls need to behave differently at runtime dependending on whenever the receiver is instantiated as ref type or as a vtype.
5161          * 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
5162          * pack the arguments into an array, and do the rest of the work in in an icall.
5163          */
5164         if (((cmethod->klass == mono_defaults.object_class) || (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) &&
5165                 (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)) &&
5166                 (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]))))) {
5167                 MonoInst *args [16];
5168
5169                 /*
5170                  * This case handles calls to
5171                  * - object:ToString()/Equals()/GetHashCode(),
5172                  * - System.IComparable<T>:CompareTo()
5173                  * - System.IEquatable<T>:Equals ()
5174                  * plus some simple interface calls enough to support AsyncTaskMethodBuilder.
5175                  */
5176
5177                 args [0] = sp [0];
5178                 if (mono_method_check_context_used (cmethod))
5179                         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cmethod), cmethod, MONO_RGCTX_INFO_METHOD);
5180                 else
5181                         EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
5182                 args [2] = emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_class), constrained_class, MONO_RGCTX_INFO_KLASS);
5183
5184                 /* !fsig->hasthis is for the wrapper for the Object.GetType () icall */
5185                 if (fsig->hasthis && fsig->param_count) {
5186                         /* Pass the arguments using a localloc-ed array using the format expected by runtime_invoke () */
5187                         MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
5188                         ins->dreg = alloc_preg (cfg);
5189                         ins->inst_imm = fsig->param_count * sizeof (mgreg_t);
5190                         MONO_ADD_INS (cfg->cbb, ins);
5191                         args [4] = ins;
5192
5193                         if (mini_is_gsharedvt_type (fsig->params [0])) {
5194                                 int addr_reg, deref_arg_reg;
5195
5196                                 ins = emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
5197                                 deref_arg_reg = alloc_preg (cfg);
5198                                 /* deref_arg = BOX_TYPE != MONO_GSHAREDVT_BOX_TYPE_VTYPE */
5199                                 EMIT_NEW_BIALU_IMM (cfg, args [3], OP_ISUB_IMM, deref_arg_reg, ins->dreg, 1);
5200
5201                                 EMIT_NEW_VARLOADA_VREG (cfg, ins, sp [1]->dreg, fsig->params [0]);
5202                                 addr_reg = ins->dreg;
5203                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, addr_reg);
5204                         } else {
5205                                 EMIT_NEW_ICONST (cfg, args [3], 0);
5206                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, sp [1]->dreg);
5207                         }
5208                 } else {
5209                         EMIT_NEW_ICONST (cfg, args [3], 0);
5210                         EMIT_NEW_ICONST (cfg, args [4], 0);
5211                 }
5212                 ins = mono_emit_jit_icall (cfg, mono_gsharedvt_constrained_call, args);
5213                 emit_widen = FALSE;
5214
5215                 if (mini_is_gsharedvt_type (fsig->ret)) {
5216                         ins = handle_unbox_gsharedvt (cfg, mono_class_from_mono_type (fsig->ret), ins);
5217                 } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret)) {
5218                         MonoInst *add;
5219
5220                         /* Unbox */
5221                         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), ins->dreg, sizeof (MonoObject));
5222                         MONO_ADD_INS (cfg->cbb, add);
5223                         /* Load value */
5224                         NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, add->dreg, 0);
5225                         MONO_ADD_INS (cfg->cbb, ins);
5226                         /* ins represents the call result */
5227                 }
5228         } else {
5229                 GSHAREDVT_FAILURE (CEE_CALLVIRT);
5230         }
5231
5232         *ref_emit_widen = emit_widen;
5233
5234         return ins;
5235
5236  exception_exit:
5237         return NULL;
5238 }
5239
5240 static void
5241 mono_emit_load_got_addr (MonoCompile *cfg)
5242 {
5243         MonoInst *getaddr, *dummy_use;
5244
5245         if (!cfg->got_var || cfg->got_var_allocated)
5246                 return;
5247
5248         MONO_INST_NEW (cfg, getaddr, OP_LOAD_GOTADDR);
5249         getaddr->cil_code = cfg->header->code;
5250         getaddr->dreg = cfg->got_var->dreg;
5251
5252         /* Add it to the start of the first bblock */
5253         if (cfg->bb_entry->code) {
5254                 getaddr->next = cfg->bb_entry->code;
5255                 cfg->bb_entry->code = getaddr;
5256         }
5257         else
5258                 MONO_ADD_INS (cfg->bb_entry, getaddr);
5259
5260         cfg->got_var_allocated = TRUE;
5261
5262         /* 
5263          * Add a dummy use to keep the got_var alive, since real uses might
5264          * only be generated by the back ends.
5265          * Add it to end_bblock, so the variable's lifetime covers the whole
5266          * method.
5267          * It would be better to make the usage of the got var explicit in all
5268          * cases when the backend needs it (i.e. calls, throw etc.), so this
5269          * wouldn't be needed.
5270          */
5271         NEW_DUMMY_USE (cfg, dummy_use, cfg->got_var);
5272         MONO_ADD_INS (cfg->bb_exit, dummy_use);
5273 }
5274
5275 static int inline_limit;
5276 static gboolean inline_limit_inited;
5277
5278 static gboolean
5279 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
5280 {
5281         MonoMethodHeaderSummary header;
5282         MonoVTable *vtable;
5283 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5284         MonoMethodSignature *sig = mono_method_signature (method);
5285         int i;
5286 #endif
5287
5288         if (cfg->disable_inline)
5289                 return FALSE;
5290         if (cfg->gshared)
5291                 return FALSE;
5292
5293         if (cfg->inline_depth > 10)
5294                 return FALSE;
5295
5296         if (!mono_method_get_header_summary (method, &header))
5297                 return FALSE;
5298
5299         /*runtime, icall and pinvoke are checked by summary call*/
5300         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
5301             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
5302             (mono_class_is_marshalbyref (method->klass)) ||
5303             header.has_clauses)
5304                 return FALSE;
5305
5306         /* also consider num_locals? */
5307         /* Do the size check early to avoid creating vtables */
5308         if (!inline_limit_inited) {
5309                 if (g_getenv ("MONO_INLINELIMIT"))
5310                         inline_limit = atoi (g_getenv ("MONO_INLINELIMIT"));
5311                 else
5312                         inline_limit = INLINE_LENGTH_LIMIT;
5313                 inline_limit_inited = TRUE;
5314         }
5315         if (header.code_size >= inline_limit && !(method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
5316                 return FALSE;
5317
5318         /*
5319          * if we can initialize the class of the method right away, we do,
5320          * otherwise we don't allow inlining if the class needs initialization,
5321          * since it would mean inserting a call to mono_runtime_class_init()
5322          * inside the inlined code
5323          */
5324         if (!(cfg->opt & MONO_OPT_SHARED)) {
5325                 /* The AggressiveInlining hint is a good excuse to force that cctor to run. */
5326                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING) {
5327                         vtable = mono_class_vtable (cfg->domain, method->klass);
5328                         if (!vtable)
5329                                 return FALSE;
5330                         if (!cfg->compile_aot) {
5331                                 MonoError error;
5332                                 if (!mono_runtime_class_init_full (vtable, &error))
5333                                         mono_error_raise_exception (&error); /* FIXME don't raise here */
5334                         }
5335                 } else if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5336                         if (cfg->run_cctors && method->klass->has_cctor) {
5337                                 /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
5338                                 if (!method->klass->runtime_info)
5339                                         /* No vtable created yet */
5340                                         return FALSE;
5341                                 vtable = mono_class_vtable (cfg->domain, method->klass);
5342                                 if (!vtable)
5343                                         return FALSE;
5344                                 /* This makes so that inline cannot trigger */
5345                                 /* .cctors: too many apps depend on them */
5346                                 /* running with a specific order... */
5347                                 if (! vtable->initialized)
5348                                         return FALSE;
5349                                 MonoError error;
5350                                 if (!mono_runtime_class_init_full (vtable, &error))
5351                                         mono_error_raise_exception (&error); /* FIXME don't raise here */
5352                         }
5353                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
5354                         if (!method->klass->runtime_info)
5355                                 /* No vtable created yet */
5356                                 return FALSE;
5357                         vtable = mono_class_vtable (cfg->domain, method->klass);
5358                         if (!vtable)
5359                                 return FALSE;
5360                         if (!vtable->initialized)
5361                                 return FALSE;
5362                 }
5363         } else {
5364                 /* 
5365                  * If we're compiling for shared code
5366                  * the cctor will need to be run at aot method load time, for example,
5367                  * or at the end of the compilation of the inlining method.
5368                  */
5369                 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
5370                         return FALSE;
5371         }
5372
5373 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5374         if (mono_arch_is_soft_float ()) {
5375                 /* FIXME: */
5376                 if (sig->ret && sig->ret->type == MONO_TYPE_R4)
5377                         return FALSE;
5378                 for (i = 0; i < sig->param_count; ++i)
5379                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
5380                                 return FALSE;
5381         }
5382 #endif
5383
5384         if (g_list_find (cfg->dont_inline, method))
5385                 return FALSE;
5386
5387         return TRUE;
5388 }
5389
5390 static gboolean
5391 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoClass *klass, MonoVTable *vtable)
5392 {
5393         if (!cfg->compile_aot) {
5394                 g_assert (vtable);
5395                 if (vtable->initialized)
5396                         return FALSE;
5397         }
5398
5399         if (klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5400                 if (cfg->method == method)
5401                         return FALSE;
5402         }
5403
5404         if (!mono_class_needs_cctor_run (klass, method))
5405                 return FALSE;
5406
5407         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (klass == method->klass))
5408                 /* The initialization is already done before the method is called */
5409                 return FALSE;
5410
5411         return TRUE;
5412 }
5413
5414 static MonoInst*
5415 mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
5416 {
5417         MonoInst *ins;
5418         guint32 size;
5419         int mult_reg, add_reg, array_reg, index_reg, index2_reg;
5420         int context_used;
5421
5422         if (mini_is_gsharedvt_variable_klass (klass)) {
5423                 size = -1;
5424         } else {
5425                 mono_class_init (klass);
5426                 size = mono_class_array_element_size (klass);
5427         }
5428
5429         mult_reg = alloc_preg (cfg);
5430         array_reg = arr->dreg;
5431         index_reg = index->dreg;
5432
5433 #if SIZEOF_REGISTER == 8
5434         /* The array reg is 64 bits but the index reg is only 32 */
5435         if (COMPILE_LLVM (cfg)) {
5436                 /* Not needed */
5437                 index2_reg = index_reg;
5438         } else {
5439                 index2_reg = alloc_preg (cfg);
5440                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
5441         }
5442 #else
5443         if (index->type == STACK_I8) {
5444                 index2_reg = alloc_preg (cfg);
5445                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I4, index2_reg, index_reg);
5446         } else {
5447                 index2_reg = index_reg;
5448         }
5449 #endif
5450
5451         if (bcheck)
5452                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
5453
5454 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5455         if (size == 1 || size == 2 || size == 4 || size == 8) {
5456                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
5457
5458                 EMIT_NEW_X86_LEA (cfg, ins, array_reg, index2_reg, fast_log2 [size], MONO_STRUCT_OFFSET (MonoArray, vector));
5459                 ins->klass = mono_class_get_element_class (klass);
5460                 ins->type = STACK_MP;
5461
5462                 return ins;
5463         }
5464 #endif          
5465
5466         add_reg = alloc_ireg_mp (cfg);
5467
5468         if (size == -1) {
5469                 MonoInst *rgctx_ins;
5470
5471                 /* gsharedvt */
5472                 g_assert (cfg->gshared);
5473                 context_used = mini_class_check_context_used (cfg, klass);
5474                 g_assert (context_used);
5475                 rgctx_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE);
5476                 MONO_EMIT_NEW_BIALU (cfg, OP_IMUL, mult_reg, index2_reg, rgctx_ins->dreg);
5477         } else {
5478                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
5479         }
5480         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
5481         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5482         ins->klass = mono_class_get_element_class (klass);
5483         ins->type = STACK_MP;
5484         MONO_ADD_INS (cfg->cbb, ins);
5485
5486         return ins;
5487 }
5488
5489 static MonoInst*
5490 mini_emit_ldelema_2_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index_ins1, MonoInst *index_ins2)
5491 {
5492         int bounds_reg = alloc_preg (cfg);
5493         int add_reg = alloc_ireg_mp (cfg);
5494         int mult_reg = alloc_preg (cfg);
5495         int mult2_reg = alloc_preg (cfg);
5496         int low1_reg = alloc_preg (cfg);
5497         int low2_reg = alloc_preg (cfg);
5498         int high1_reg = alloc_preg (cfg);
5499         int high2_reg = alloc_preg (cfg);
5500         int realidx1_reg = alloc_preg (cfg);
5501         int realidx2_reg = alloc_preg (cfg);
5502         int sum_reg = alloc_preg (cfg);
5503         int index1, index2, tmpreg;
5504         MonoInst *ins;
5505         guint32 size;
5506
5507         mono_class_init (klass);
5508         size = mono_class_array_element_size (klass);
5509
5510         index1 = index_ins1->dreg;
5511         index2 = index_ins2->dreg;
5512
5513 #if SIZEOF_REGISTER == 8
5514         /* The array reg is 64 bits but the index reg is only 32 */
5515         if (COMPILE_LLVM (cfg)) {
5516                 /* Not needed */
5517         } else {
5518                 tmpreg = alloc_preg (cfg);
5519                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index1);
5520                 index1 = tmpreg;
5521                 tmpreg = alloc_preg (cfg);
5522                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index2);
5523                 index2 = tmpreg;
5524         }
5525 #else
5526         // FIXME: Do we need to do something here for i8 indexes, like in ldelema_1_ins ?
5527         tmpreg = -1;
5528 #endif
5529
5530         /* range checking */
5531         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, 
5532                                        arr->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5533
5534         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low1_reg, 
5535                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5536         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx1_reg, index1, low1_reg);
5537         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high1_reg, 
5538                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5539         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high1_reg, realidx1_reg);
5540         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5541
5542         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low2_reg, 
5543                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5544         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx2_reg, index2, low2_reg);
5545         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high2_reg, 
5546                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5547         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high2_reg, realidx2_reg);
5548         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5549
5550         MONO_EMIT_NEW_BIALU (cfg, OP_PMUL, mult_reg, high2_reg, realidx1_reg);
5551         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, mult_reg, realidx2_reg);
5552         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PMUL_IMM, mult2_reg, sum_reg, size);
5553         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult2_reg, arr->dreg);
5554         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5555
5556         ins->type = STACK_MP;
5557         ins->klass = klass;
5558         MONO_ADD_INS (cfg->cbb, ins);
5559
5560         return ins;
5561 }
5562
5563 static MonoInst*
5564 mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
5565 {
5566         int rank;
5567         MonoInst *addr;
5568         MonoMethod *addr_method;
5569         int element_size;
5570         MonoClass *eclass = cmethod->klass->element_class;
5571
5572         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
5573
5574         if (rank == 1)
5575                 return mini_emit_ldelema_1_ins (cfg, eclass, sp [0], sp [1], TRUE);
5576
5577         /* emit_ldelema_2 depends on OP_LMUL */
5578         if (!cfg->backend->emulate_mul_div && rank == 2 && (cfg->opt & MONO_OPT_INTRINS) && !mini_is_gsharedvt_variable_klass (eclass)) {
5579                 return mini_emit_ldelema_2_ins (cfg, eclass, sp [0], sp [1], sp [2]);
5580         }
5581
5582         if (mini_is_gsharedvt_variable_klass (eclass))
5583                 element_size = 0;
5584         else
5585                 element_size = mono_class_array_element_size (eclass);
5586         addr_method = mono_marshal_get_array_address (rank, element_size);
5587         addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
5588
5589         return addr;
5590 }
5591
5592 static MonoBreakPolicy
5593 always_insert_breakpoint (MonoMethod *method)
5594 {
5595         return MONO_BREAK_POLICY_ALWAYS;
5596 }
5597
5598 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
5599
5600 /**
5601  * mono_set_break_policy:
5602  * policy_callback: the new callback function
5603  *
5604  * Allow embedders to decide wherther to actually obey breakpoint instructions
5605  * (both break IL instructions and Debugger.Break () method calls), for example
5606  * to not allow an app to be aborted by a perfectly valid IL opcode when executing
5607  * untrusted or semi-trusted code.
5608  *
5609  * @policy_callback will be called every time a break point instruction needs to
5610  * be inserted with the method argument being the method that calls Debugger.Break()
5611  * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
5612  * if it wants the breakpoint to not be effective in the given method.
5613  * #MONO_BREAK_POLICY_ALWAYS is the default.
5614  */
5615 void
5616 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
5617 {
5618         if (policy_callback)
5619                 break_policy_func = policy_callback;
5620         else
5621                 break_policy_func = always_insert_breakpoint;
5622 }
5623
5624 static gboolean
5625 should_insert_brekpoint (MonoMethod *method) {
5626         switch (break_policy_func (method)) {
5627         case MONO_BREAK_POLICY_ALWAYS:
5628                 return TRUE;
5629         case MONO_BREAK_POLICY_NEVER:
5630                 return FALSE;
5631         case MONO_BREAK_POLICY_ON_DBG:
5632                 g_warning ("mdb no longer supported");
5633                 return FALSE;
5634         default:
5635                 g_warning ("Incorrect value returned from break policy callback");
5636                 return FALSE;
5637         }
5638 }
5639
5640 /* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
5641 static MonoInst*
5642 emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5643 {
5644         MonoInst *addr, *store, *load;
5645         MonoClass *eklass = mono_class_from_mono_type (fsig->params [2]);
5646
5647         /* the bounds check is already done by the callers */
5648         addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5649         if (is_set) {
5650                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
5651                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
5652                 if (mini_type_is_reference (fsig->params [2]))
5653                         emit_write_barrier (cfg, addr, load);
5654         } else {
5655                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
5656                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
5657         }
5658         return store;
5659 }
5660
5661
5662 static gboolean
5663 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
5664 {
5665         return mini_type_is_reference (&klass->byval_arg);
5666 }
5667
5668 static MonoInst*
5669 emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean safety_checks)
5670 {
5671         if (safety_checks && generic_class_is_reference_type (cfg, klass) &&
5672                 !(sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL)) {
5673                 MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
5674                 MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
5675                 MonoInst *iargs [3];
5676
5677                 if (!helper->slot)
5678                         mono_class_setup_vtable (obj_array);
5679                 g_assert (helper->slot);
5680
5681                 if (sp [0]->type != STACK_OBJ)
5682                         return NULL;
5683                 if (sp [2]->type != STACK_OBJ)
5684                         return NULL;
5685
5686                 iargs [2] = sp [2];
5687                 iargs [1] = sp [1];
5688                 iargs [0] = sp [0];
5689
5690                 return mono_emit_method_call (cfg, helper, iargs, sp [0]);
5691         } else {
5692                 MonoInst *ins;
5693
5694                 if (mini_is_gsharedvt_variable_klass (klass)) {
5695                         MonoInst *addr;
5696
5697                         // FIXME-VT: OP_ICONST optimization
5698                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
5699                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5700                         ins->opcode = OP_STOREV_MEMBASE;
5701                 } else if (sp [1]->opcode == OP_ICONST) {
5702                         int array_reg = sp [0]->dreg;
5703                         int index_reg = sp [1]->dreg;
5704                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
5705
5706                         if (SIZEOF_REGISTER == 8 && COMPILE_LLVM (cfg))
5707                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, index_reg);
5708
5709                         if (safety_checks)
5710                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
5711                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
5712                 } else {
5713                         MonoInst *addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], safety_checks);
5714                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5715                         if (generic_class_is_reference_type (cfg, klass))
5716                                 emit_write_barrier (cfg, addr, sp [2]);
5717                 }
5718                 return ins;
5719         }
5720 }
5721
5722 static MonoInst*
5723 emit_array_unsafe_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5724 {
5725         MonoClass *eklass;
5726         
5727         if (is_set)
5728                 eklass = mono_class_from_mono_type (fsig->params [2]);
5729         else
5730                 eklass = mono_class_from_mono_type (fsig->ret);
5731
5732         if (is_set) {
5733                 return emit_array_store (cfg, eklass, args, FALSE);
5734         } else {
5735                 MonoInst *ins, *addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5736                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &eklass->byval_arg, addr->dreg, 0);
5737                 return ins;
5738         }
5739 }
5740
5741 static gboolean
5742 is_unsafe_mov_compatible (MonoCompile *cfg, MonoClass *param_klass, MonoClass *return_klass)
5743 {
5744         uint32_t align;
5745         int param_size, return_size;
5746
5747         param_klass = mono_class_from_mono_type (mini_get_underlying_type (&param_klass->byval_arg));
5748         return_klass = mono_class_from_mono_type (mini_get_underlying_type (&return_klass->byval_arg));
5749
5750         if (cfg->verbose_level > 3)
5751                 printf ("[UNSAFE-MOV-INTRISIC] %s <- %s\n", return_klass->name, param_klass->name);
5752
5753         //Don't allow mixing reference types with value types
5754         if (param_klass->valuetype != return_klass->valuetype) {
5755                 if (cfg->verbose_level > 3)
5756                         printf ("[UNSAFE-MOV-INTRISIC]\tone of the args is a valuetype and the other is not\n");
5757                 return FALSE;
5758         }
5759
5760         if (!param_klass->valuetype) {
5761                 if (cfg->verbose_level > 3)
5762                         printf ("[UNSAFE-MOV-INTRISIC]\targs are reference types\n");
5763                 return TRUE;
5764         }
5765
5766         //That are blitable
5767         if (param_klass->has_references || return_klass->has_references)
5768                 return FALSE;
5769
5770         /* Avoid mixing structs and primitive types/enums, they need to be handled differently in the JIT */
5771         if ((MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && !MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)) ||
5772                 (!MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && MONO_TYPE_ISSTRUCT (&return_klass->byval_arg))) {
5773                         if (cfg->verbose_level > 3)
5774                                 printf ("[UNSAFE-MOV-INTRISIC]\tmixing structs and scalars\n");
5775                 return FALSE;
5776         }
5777
5778         if (param_klass->byval_arg.type == MONO_TYPE_R4 || param_klass->byval_arg.type == MONO_TYPE_R8 ||
5779                 return_klass->byval_arg.type == MONO_TYPE_R4 || return_klass->byval_arg.type == MONO_TYPE_R8) {
5780                 if (cfg->verbose_level > 3)
5781                         printf ("[UNSAFE-MOV-INTRISIC]\tfloat or double are not supported\n");
5782                 return FALSE;
5783         }
5784
5785         param_size = mono_class_value_size (param_klass, &align);
5786         return_size = mono_class_value_size (return_klass, &align);
5787
5788         //We can do it if sizes match
5789         if (param_size == return_size) {
5790                 if (cfg->verbose_level > 3)
5791                         printf ("[UNSAFE-MOV-INTRISIC]\tsame size\n");
5792                 return TRUE;
5793         }
5794
5795         //No simple way to handle struct if sizes don't match
5796         if (MONO_TYPE_ISSTRUCT (&param_klass->byval_arg)) {
5797                 if (cfg->verbose_level > 3)
5798                         printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch and type is a struct\n");
5799                 return FALSE;
5800         }
5801
5802         /*
5803          * Same reg size category.
5804          * A quick note on why we don't require widening here.
5805          * The intrinsic is "R Array.UnsafeMov<S,R> (S s)".
5806          *
5807          * Since the source value comes from a function argument, the JIT will already have
5808          * the value in a VREG and performed any widening needed before (say, when loading from a field).
5809          */
5810         if (param_size <= 4 && return_size <= 4) {
5811                 if (cfg->verbose_level > 3)
5812                         printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch but both are of the same reg class\n");
5813                 return TRUE;
5814         }
5815
5816         return FALSE;
5817 }
5818
5819 static MonoInst*
5820 emit_array_unsafe_mov (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args)
5821 {
5822         MonoClass *param_klass = mono_class_from_mono_type (fsig->params [0]);
5823         MonoClass *return_klass = mono_class_from_mono_type (fsig->ret);
5824
5825         if (mini_is_gsharedvt_variable_type (fsig->ret))
5826                 return NULL;
5827
5828         //Valuetypes that are semantically equivalent or numbers than can be widened to
5829         if (is_unsafe_mov_compatible (cfg, param_klass, return_klass))
5830                 return args [0];
5831
5832         //Arrays of valuetypes that are semantically equivalent
5833         if (param_klass->rank == 1 && return_klass->rank == 1 && is_unsafe_mov_compatible (cfg, param_klass->element_class, return_klass->element_class))
5834                 return args [0];
5835
5836         return NULL;
5837 }
5838
5839 static MonoInst*
5840 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5841 {
5842 #ifdef MONO_ARCH_SIMD_INTRINSICS
5843         MonoInst *ins = NULL;
5844
5845         if (cfg->opt & MONO_OPT_SIMD) {
5846                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5847                 if (ins)
5848                         return ins;
5849         }
5850 #endif
5851
5852         return mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5853 }
5854
5855 static MonoInst*
5856 emit_memory_barrier (MonoCompile *cfg, int kind)
5857 {
5858         MonoInst *ins = NULL;
5859         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
5860         MONO_ADD_INS (cfg->cbb, ins);
5861         ins->backend.memory_barrier_kind = kind;
5862
5863         return ins;
5864 }
5865
5866 static MonoInst*
5867 llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5868 {
5869         MonoInst *ins = NULL;
5870         int opcode = 0;
5871
5872         /* The LLVM backend supports these intrinsics */
5873         if (cmethod->klass == mono_defaults.math_class) {
5874                 if (strcmp (cmethod->name, "Sin") == 0) {
5875                         opcode = OP_SIN;
5876                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5877                         opcode = OP_COS;
5878                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
5879                         opcode = OP_SQRT;
5880                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5881                         opcode = OP_ABS;
5882                 }
5883
5884                 if (opcode && fsig->param_count == 1) {
5885                         MONO_INST_NEW (cfg, ins, opcode);
5886                         ins->type = STACK_R8;
5887                         ins->dreg = mono_alloc_freg (cfg);
5888                         ins->sreg1 = args [0]->dreg;
5889                         MONO_ADD_INS (cfg->cbb, ins);
5890                 }
5891
5892                 opcode = 0;
5893                 if (cfg->opt & MONO_OPT_CMOV) {
5894                         if (strcmp (cmethod->name, "Min") == 0) {
5895                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5896                                         opcode = OP_IMIN;
5897                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5898                                         opcode = OP_IMIN_UN;
5899                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5900                                         opcode = OP_LMIN;
5901                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5902                                         opcode = OP_LMIN_UN;
5903                         } else if (strcmp (cmethod->name, "Max") == 0) {
5904                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5905                                         opcode = OP_IMAX;
5906                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5907                                         opcode = OP_IMAX_UN;
5908                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5909                                         opcode = OP_LMAX;
5910                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5911                                         opcode = OP_LMAX_UN;
5912                         }
5913                 }
5914
5915                 if (opcode && fsig->param_count == 2) {
5916                         MONO_INST_NEW (cfg, ins, opcode);
5917                         ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
5918                         ins->dreg = mono_alloc_ireg (cfg);
5919                         ins->sreg1 = args [0]->dreg;
5920                         ins->sreg2 = args [1]->dreg;
5921                         MONO_ADD_INS (cfg->cbb, ins);
5922                 }
5923         }
5924
5925         return ins;
5926 }
5927
5928 static MonoInst*
5929 mini_emit_inst_for_sharable_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5930 {
5931         if (cmethod->klass == mono_defaults.array_class) {
5932                 if (strcmp (cmethod->name, "UnsafeStore") == 0)
5933                         return emit_array_unsafe_access (cfg, fsig, args, TRUE);
5934                 else if (strcmp (cmethod->name, "UnsafeLoad") == 0)
5935                         return emit_array_unsafe_access (cfg, fsig, args, FALSE);
5936                 else if (strcmp (cmethod->name, "UnsafeMov") == 0)
5937                         return emit_array_unsafe_mov (cfg, fsig, args);
5938         }
5939
5940         return NULL;
5941 }
5942
5943 static MonoInst*
5944 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5945 {
5946         MonoInst *ins = NULL;
5947
5948          MonoClass *runtime_helpers_class = mono_class_get_runtime_helpers_class ();
5949
5950         if (cmethod->klass == mono_defaults.string_class) {
5951                 if (strcmp (cmethod->name, "get_Chars") == 0 && fsig->param_count + fsig->hasthis == 2) {
5952                         int dreg = alloc_ireg (cfg);
5953                         int index_reg = alloc_preg (cfg);
5954                         int add_reg = alloc_preg (cfg);
5955
5956 #if SIZEOF_REGISTER == 8
5957                         if (COMPILE_LLVM (cfg)) {
5958                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, args [1]->dreg);
5959                         } else {
5960                                 /* The array reg is 64 bits but the index reg is only 32 */
5961                                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
5962                         }
5963 #else
5964                         index_reg = args [1]->dreg;
5965 #endif  
5966                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
5967
5968 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5969                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, MONO_STRUCT_OFFSET (MonoString, chars));
5970                         add_reg = ins->dreg;
5971                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5972                                                                    add_reg, 0);
5973 #else
5974                         int mult_reg = alloc_preg (cfg);
5975                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
5976                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5977                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5978                                                                    add_reg, MONO_STRUCT_OFFSET (MonoString, chars));
5979 #endif
5980                         type_from_op (cfg, ins, NULL, NULL);
5981                         return ins;
5982                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
5983                         int dreg = alloc_ireg (cfg);
5984                         /* Decompose later to allow more optimizations */
5985                         EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
5986                         ins->type = STACK_I4;
5987                         ins->flags |= MONO_INST_FAULT;
5988                         cfg->cbb->has_array_access = TRUE;
5989                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
5990
5991                         return ins;
5992                 } else 
5993                         return NULL;
5994         } else if (cmethod->klass == mono_defaults.object_class) {
5995                 if (strcmp (cmethod->name, "GetType") == 0 && fsig->param_count + fsig->hasthis == 1) {
5996                         int dreg = alloc_ireg_ref (cfg);
5997                         int vt_reg = alloc_preg (cfg);
5998                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5999                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, MONO_STRUCT_OFFSET (MonoVTable, type));
6000                         type_from_op (cfg, ins, NULL, NULL);
6001
6002                         return ins;
6003                 } else if (!cfg->backend->emulate_mul_div && strcmp (cmethod->name, "InternalGetHashCode") == 0 && fsig->param_count == 1 && !mono_gc_is_moving ()) {
6004                         int dreg = alloc_ireg (cfg);
6005                         int t1 = alloc_ireg (cfg);
6006         
6007                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
6008                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
6009                         ins->type = STACK_I4;
6010
6011                         return ins;
6012                 } else if (strcmp (cmethod->name, ".ctor") == 0 && fsig->param_count == 0) {
6013                         MONO_INST_NEW (cfg, ins, OP_NOP);
6014                         MONO_ADD_INS (cfg->cbb, ins);
6015                         return ins;
6016                 } else
6017                         return NULL;
6018         } else if (cmethod->klass == mono_defaults.array_class) {
6019                 if (strcmp (cmethod->name, "GetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
6020                         return emit_array_generic_access (cfg, fsig, args, FALSE);
6021                 else if (strcmp (cmethod->name, "SetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
6022                         return emit_array_generic_access (cfg, fsig, args, TRUE);
6023
6024 #ifndef MONO_BIG_ARRAYS
6025                 /*
6026                  * This is an inline version of GetLength/GetLowerBound(0) used frequently in
6027                  * Array methods.
6028                  */
6029                 else if (((strcmp (cmethod->name, "GetLength") == 0 && fsig->param_count + fsig->hasthis == 2) ||
6030                          (strcmp (cmethod->name, "GetLowerBound") == 0 && fsig->param_count + fsig->hasthis == 2)) &&
6031                          args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) {
6032                         int dreg = alloc_ireg (cfg);
6033                         int bounds_reg = alloc_ireg_mp (cfg);
6034                         MonoBasicBlock *end_bb, *szarray_bb;
6035                         gboolean get_length = strcmp (cmethod->name, "GetLength") == 0;
6036
6037                         NEW_BBLOCK (cfg, end_bb);
6038                         NEW_BBLOCK (cfg, szarray_bb);
6039
6040                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOAD_MEMBASE, bounds_reg,
6041                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
6042                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
6043                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, szarray_bb);
6044                         /* Non-szarray case */
6045                         if (get_length)
6046                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
6047                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
6048                         else
6049                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
6050                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
6051                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
6052                         MONO_START_BB (cfg, szarray_bb);
6053                         /* Szarray case */
6054                         if (get_length)
6055                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
6056                                                                            args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
6057                         else
6058                                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
6059                         MONO_START_BB (cfg, end_bb);
6060
6061                         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg);
6062                         ins->type = STACK_I4;
6063                         
6064                         return ins;
6065                 }
6066 #endif
6067
6068                 if (cmethod->name [0] != 'g')
6069                         return NULL;
6070
6071                 if (strcmp (cmethod->name, "get_Rank") == 0 && fsig->param_count + fsig->hasthis == 1) {
6072                         int dreg = alloc_ireg (cfg);
6073                         int vtable_reg = alloc_preg (cfg);
6074                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
6075                                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
6076                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
6077                                                                    vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
6078                         type_from_op (cfg, ins, NULL, NULL);
6079
6080                         return ins;
6081                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
6082                         int dreg = alloc_ireg (cfg);
6083
6084                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
6085                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
6086                         type_from_op (cfg, ins, NULL, NULL);
6087
6088                         return ins;
6089                 } else
6090                         return NULL;
6091         } else if (cmethod->klass == runtime_helpers_class) {
6092                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0 && fsig->param_count == 0) {
6093                         EMIT_NEW_ICONST (cfg, ins, MONO_STRUCT_OFFSET (MonoString, chars));
6094                         return ins;
6095                 } else
6096                         return NULL;
6097         } else if (cmethod->klass == mono_defaults.monitor_class) {
6098                 gboolean is_enter = FALSE;
6099                 gboolean is_v4 = FALSE;
6100
6101                 if (!strcmp (cmethod->name, "enter_with_atomic_var") && mono_method_signature (cmethod)->param_count == 2) {
6102                         is_enter = TRUE;
6103                         is_v4 = TRUE;
6104                 }
6105                 if (!strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1)
6106                         is_enter = TRUE;
6107
6108                 if (is_enter) {
6109                         /*
6110                          * To make async stack traces work, icalls which can block should have a wrapper.
6111                          * For Monitor.Enter, emit two calls: a fastpath which doesn't have a wrapper, and a slowpath, which does.
6112                          */
6113                         MonoBasicBlock *end_bb;
6114
6115                         NEW_BBLOCK (cfg, end_bb);
6116
6117                         ins = mono_emit_jit_icall (cfg, is_v4 ? (gpointer)mono_monitor_enter_v4_fast : (gpointer)mono_monitor_enter_fast, args);
6118                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, ins->dreg, 0);
6119                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, end_bb);
6120                         ins = mono_emit_jit_icall (cfg, is_v4 ? (gpointer)mono_monitor_enter_v4 : (gpointer)mono_monitor_enter, args);
6121                         MONO_START_BB (cfg, end_bb);
6122                         return ins;
6123                 }
6124         } else if (cmethod->klass == mono_defaults.thread_class) {
6125                 if (strcmp (cmethod->name, "SpinWait_nop") == 0 && fsig->param_count == 0) {
6126                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
6127                         MONO_ADD_INS (cfg->cbb, ins);
6128                         return ins;
6129                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0) {
6130                         return emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6131                 } else if (!strcmp (cmethod->name, "VolatileRead") && fsig->param_count == 1) {
6132                         guint32 opcode = 0;
6133                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6134
6135                         if (fsig->params [0]->type == MONO_TYPE_I1)
6136                                 opcode = OP_LOADI1_MEMBASE;
6137                         else if (fsig->params [0]->type == MONO_TYPE_U1)
6138                                 opcode = OP_LOADU1_MEMBASE;
6139                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6140                                 opcode = OP_LOADI2_MEMBASE;
6141                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6142                                 opcode = OP_LOADU2_MEMBASE;
6143                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6144                                 opcode = OP_LOADI4_MEMBASE;
6145                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6146                                 opcode = OP_LOADU4_MEMBASE;
6147                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
6148                                 opcode = OP_LOADI8_MEMBASE;
6149                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6150                                 opcode = OP_LOADR4_MEMBASE;
6151                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6152                                 opcode = OP_LOADR8_MEMBASE;
6153                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
6154                                 opcode = OP_LOAD_MEMBASE;
6155
6156                         if (opcode) {
6157                                 MONO_INST_NEW (cfg, ins, opcode);
6158                                 ins->inst_basereg = args [0]->dreg;
6159                                 ins->inst_offset = 0;
6160                                 MONO_ADD_INS (cfg->cbb, ins);
6161
6162                                 switch (fsig->params [0]->type) {
6163                                 case MONO_TYPE_I1:
6164                                 case MONO_TYPE_U1:
6165                                 case MONO_TYPE_I2:
6166                                 case MONO_TYPE_U2:
6167                                 case MONO_TYPE_I4:
6168                                 case MONO_TYPE_U4:
6169                                         ins->dreg = mono_alloc_ireg (cfg);
6170                                         ins->type = STACK_I4;
6171                                         break;
6172                                 case MONO_TYPE_I8:
6173                                 case MONO_TYPE_U8:
6174                                         ins->dreg = mono_alloc_lreg (cfg);
6175                                         ins->type = STACK_I8;
6176                                         break;
6177                                 case MONO_TYPE_I:
6178                                 case MONO_TYPE_U:
6179                                         ins->dreg = mono_alloc_ireg (cfg);
6180 #if SIZEOF_REGISTER == 8
6181                                         ins->type = STACK_I8;
6182 #else
6183                                         ins->type = STACK_I4;
6184 #endif
6185                                         break;
6186                                 case MONO_TYPE_R4:
6187                                 case MONO_TYPE_R8:
6188                                         ins->dreg = mono_alloc_freg (cfg);
6189                                         ins->type = STACK_R8;
6190                                         break;
6191                                 default:
6192                                         g_assert (mini_type_is_reference (fsig->params [0]));
6193                                         ins->dreg = mono_alloc_ireg_ref (cfg);
6194                                         ins->type = STACK_OBJ;
6195                                         break;
6196                                 }
6197
6198                                 if (opcode == OP_LOADI8_MEMBASE)
6199                                         ins = mono_decompose_opcode (cfg, ins);
6200
6201                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6202
6203                                 return ins;
6204                         }
6205                 } else if (!strcmp (cmethod->name, "VolatileWrite") && fsig->param_count == 2) {
6206                         guint32 opcode = 0;
6207                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6208
6209                         if (fsig->params [0]->type == MONO_TYPE_I1 || fsig->params [0]->type == MONO_TYPE_U1)
6210                                 opcode = OP_STOREI1_MEMBASE_REG;
6211                         else if (fsig->params [0]->type == MONO_TYPE_I2 || fsig->params [0]->type == MONO_TYPE_U2)
6212                                 opcode = OP_STOREI2_MEMBASE_REG;
6213                         else if (fsig->params [0]->type == MONO_TYPE_I4 || fsig->params [0]->type == MONO_TYPE_U4)
6214                                 opcode = OP_STOREI4_MEMBASE_REG;
6215                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
6216                                 opcode = OP_STOREI8_MEMBASE_REG;
6217                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6218                                 opcode = OP_STORER4_MEMBASE_REG;
6219                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6220                                 opcode = OP_STORER8_MEMBASE_REG;
6221                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
6222                                 opcode = OP_STORE_MEMBASE_REG;
6223
6224                         if (opcode) {
6225                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6226
6227                                 MONO_INST_NEW (cfg, ins, opcode);
6228                                 ins->sreg1 = args [1]->dreg;
6229                                 ins->inst_destbasereg = args [0]->dreg;
6230                                 ins->inst_offset = 0;
6231                                 MONO_ADD_INS (cfg->cbb, ins);
6232
6233                                 if (opcode == OP_STOREI8_MEMBASE_REG)
6234                                         ins = mono_decompose_opcode (cfg, ins);
6235
6236                                 return ins;
6237                         }
6238                 }
6239         } else if (cmethod->klass->image == mono_defaults.corlib &&
6240                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6241                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
6242                 ins = NULL;
6243
6244 #if SIZEOF_REGISTER == 8
6245                 if (!cfg->llvm_only && strcmp (cmethod->name, "Read") == 0 && fsig->param_count == 1 && (fsig->params [0]->type == MONO_TYPE_I8)) {
6246                         if (!cfg->llvm_only && mono_arch_opcode_supported (OP_ATOMIC_LOAD_I8)) {
6247                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_LOAD_I8);
6248                                 ins->dreg = mono_alloc_preg (cfg);
6249                                 ins->sreg1 = args [0]->dreg;
6250                                 ins->type = STACK_I8;
6251                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_SEQ;
6252                                 MONO_ADD_INS (cfg->cbb, ins);
6253                         } else {
6254                                 MonoInst *load_ins;
6255
6256                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6257
6258                                 /* 64 bit reads are already atomic */
6259                                 MONO_INST_NEW (cfg, load_ins, OP_LOADI8_MEMBASE);
6260                                 load_ins->dreg = mono_alloc_preg (cfg);
6261                                 load_ins->inst_basereg = args [0]->dreg;
6262                                 load_ins->inst_offset = 0;
6263                                 load_ins->type = STACK_I8;
6264                                 MONO_ADD_INS (cfg->cbb, load_ins);
6265
6266                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6267
6268                                 ins = load_ins;
6269                         }
6270                 }
6271 #endif
6272
6273                 if (strcmp (cmethod->name, "Increment") == 0 && fsig->param_count == 1) {
6274                         MonoInst *ins_iconst;
6275                         guint32 opcode = 0;
6276
6277                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6278                                 opcode = OP_ATOMIC_ADD_I4;
6279                                 cfg->has_atomic_add_i4 = TRUE;
6280                         }
6281 #if SIZEOF_REGISTER == 8
6282                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6283                                 opcode = OP_ATOMIC_ADD_I8;
6284 #endif
6285                         if (opcode) {
6286                                 if (!mono_arch_opcode_supported (opcode))
6287                                         return NULL;
6288                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6289                                 ins_iconst->inst_c0 = 1;
6290                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6291                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6292
6293                                 MONO_INST_NEW (cfg, ins, opcode);
6294                                 ins->dreg = mono_alloc_ireg (cfg);
6295                                 ins->inst_basereg = args [0]->dreg;
6296                                 ins->inst_offset = 0;
6297                                 ins->sreg2 = ins_iconst->dreg;
6298                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6299                                 MONO_ADD_INS (cfg->cbb, ins);
6300                         }
6301                 } else if (strcmp (cmethod->name, "Decrement") == 0 && fsig->param_count == 1) {
6302                         MonoInst *ins_iconst;
6303                         guint32 opcode = 0;
6304
6305                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6306                                 opcode = OP_ATOMIC_ADD_I4;
6307                                 cfg->has_atomic_add_i4 = TRUE;
6308                         }
6309 #if SIZEOF_REGISTER == 8
6310                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6311                                 opcode = OP_ATOMIC_ADD_I8;
6312 #endif
6313                         if (opcode) {
6314                                 if (!mono_arch_opcode_supported (opcode))
6315                                         return NULL;
6316                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6317                                 ins_iconst->inst_c0 = -1;
6318                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6319                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6320
6321                                 MONO_INST_NEW (cfg, ins, opcode);
6322                                 ins->dreg = mono_alloc_ireg (cfg);
6323                                 ins->inst_basereg = args [0]->dreg;
6324                                 ins->inst_offset = 0;
6325                                 ins->sreg2 = ins_iconst->dreg;
6326                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6327                                 MONO_ADD_INS (cfg->cbb, ins);
6328                         }
6329                 } else if (strcmp (cmethod->name, "Add") == 0 && fsig->param_count == 2) {
6330                         guint32 opcode = 0;
6331
6332                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6333                                 opcode = OP_ATOMIC_ADD_I4;
6334                                 cfg->has_atomic_add_i4 = TRUE;
6335                         }
6336 #if SIZEOF_REGISTER == 8
6337                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6338                                 opcode = OP_ATOMIC_ADD_I8;
6339 #endif
6340                         if (opcode) {
6341                                 if (!mono_arch_opcode_supported (opcode))
6342                                         return NULL;
6343                                 MONO_INST_NEW (cfg, ins, opcode);
6344                                 ins->dreg = mono_alloc_ireg (cfg);
6345                                 ins->inst_basereg = args [0]->dreg;
6346                                 ins->inst_offset = 0;
6347                                 ins->sreg2 = args [1]->dreg;
6348                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6349                                 MONO_ADD_INS (cfg->cbb, ins);
6350                         }
6351                 }
6352                 else if (strcmp (cmethod->name, "Exchange") == 0 && fsig->param_count == 2) {
6353                         MonoInst *f2i = NULL, *i2f;
6354                         guint32 opcode, f2i_opcode, i2f_opcode;
6355                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6356                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
6357
6358                         if (fsig->params [0]->type == MONO_TYPE_I4 ||
6359                             fsig->params [0]->type == MONO_TYPE_R4) {
6360                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6361                                 f2i_opcode = OP_MOVE_F_TO_I4;
6362                                 i2f_opcode = OP_MOVE_I4_TO_F;
6363                                 cfg->has_atomic_exchange_i4 = TRUE;
6364                         }
6365 #if SIZEOF_REGISTER == 8
6366                         else if (is_ref ||
6367                                  fsig->params [0]->type == MONO_TYPE_I8 ||
6368                                  fsig->params [0]->type == MONO_TYPE_R8 ||
6369                                  fsig->params [0]->type == MONO_TYPE_I) {
6370                                 opcode = OP_ATOMIC_EXCHANGE_I8;
6371                                 f2i_opcode = OP_MOVE_F_TO_I8;
6372                                 i2f_opcode = OP_MOVE_I8_TO_F;
6373                         }
6374 #else
6375                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I) {
6376                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6377                                 cfg->has_atomic_exchange_i4 = TRUE;
6378                         }
6379 #endif
6380                         else
6381                                 return NULL;
6382
6383                         if (!mono_arch_opcode_supported (opcode))
6384                                 return NULL;
6385
6386                         if (is_float) {
6387                                 /* TODO: Decompose these opcodes instead of bailing here. */
6388                                 if (COMPILE_SOFT_FLOAT (cfg))
6389                                         return NULL;
6390
6391                                 MONO_INST_NEW (cfg, f2i, f2i_opcode);
6392                                 f2i->dreg = mono_alloc_ireg (cfg);
6393                                 f2i->sreg1 = args [1]->dreg;
6394                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6395                                         f2i->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6396                                 MONO_ADD_INS (cfg->cbb, f2i);
6397                         }
6398
6399                         MONO_INST_NEW (cfg, ins, opcode);
6400                         ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg);
6401                         ins->inst_basereg = args [0]->dreg;
6402                         ins->inst_offset = 0;
6403                         ins->sreg2 = is_float ? f2i->dreg : args [1]->dreg;
6404                         MONO_ADD_INS (cfg->cbb, ins);
6405
6406                         switch (fsig->params [0]->type) {
6407                         case MONO_TYPE_I4:
6408                                 ins->type = STACK_I4;
6409                                 break;
6410                         case MONO_TYPE_I8:
6411                                 ins->type = STACK_I8;
6412                                 break;
6413                         case MONO_TYPE_I:
6414 #if SIZEOF_REGISTER == 8
6415                                 ins->type = STACK_I8;
6416 #else
6417                                 ins->type = STACK_I4;
6418 #endif
6419                                 break;
6420                         case MONO_TYPE_R4:
6421                         case MONO_TYPE_R8:
6422                                 ins->type = STACK_R8;
6423                                 break;
6424                         default:
6425                                 g_assert (mini_type_is_reference (fsig->params [0]));
6426                                 ins->type = STACK_OBJ;
6427                                 break;
6428                         }
6429
6430                         if (is_float) {
6431                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6432                                 i2f->dreg = mono_alloc_freg (cfg);
6433                                 i2f->sreg1 = ins->dreg;
6434                                 i2f->type = STACK_R8;
6435                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6436                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6437                                 MONO_ADD_INS (cfg->cbb, i2f);
6438
6439                                 ins = i2f;
6440                         }
6441
6442                         if (cfg->gen_write_barriers && is_ref)
6443                                 emit_write_barrier (cfg, args [0], args [1]);
6444                 }
6445                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 3) {
6446                         MonoInst *f2i_new = NULL, *f2i_cmp = NULL, *i2f;
6447                         guint32 opcode, f2i_opcode, i2f_opcode;
6448                         gboolean is_ref = mini_type_is_reference (fsig->params [1]);
6449                         gboolean is_float = fsig->params [1]->type == MONO_TYPE_R4 || fsig->params [1]->type == MONO_TYPE_R8;
6450
6451                         if (fsig->params [1]->type == MONO_TYPE_I4 ||
6452                             fsig->params [1]->type == MONO_TYPE_R4) {
6453                                 opcode = OP_ATOMIC_CAS_I4;
6454                                 f2i_opcode = OP_MOVE_F_TO_I4;
6455                                 i2f_opcode = OP_MOVE_I4_TO_F;
6456                                 cfg->has_atomic_cas_i4 = TRUE;
6457                         }
6458 #if SIZEOF_REGISTER == 8
6459                         else if (is_ref ||
6460                                  fsig->params [1]->type == MONO_TYPE_I8 ||
6461                                  fsig->params [1]->type == MONO_TYPE_R8 ||
6462                                  fsig->params [1]->type == MONO_TYPE_I) {
6463                                 opcode = OP_ATOMIC_CAS_I8;
6464                                 f2i_opcode = OP_MOVE_F_TO_I8;
6465                                 i2f_opcode = OP_MOVE_I8_TO_F;
6466                         }
6467 #else
6468                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I) {
6469                                 opcode = OP_ATOMIC_CAS_I4;
6470                                 cfg->has_atomic_cas_i4 = TRUE;
6471                         }
6472 #endif
6473                         else
6474                                 return NULL;
6475
6476                         if (!mono_arch_opcode_supported (opcode))
6477                                 return NULL;
6478
6479                         if (is_float) {
6480                                 /* TODO: Decompose these opcodes instead of bailing here. */
6481                                 if (COMPILE_SOFT_FLOAT (cfg))
6482                                         return NULL;
6483
6484                                 MONO_INST_NEW (cfg, f2i_new, f2i_opcode);
6485                                 f2i_new->dreg = mono_alloc_ireg (cfg);
6486                                 f2i_new->sreg1 = args [1]->dreg;
6487                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6488                                         f2i_new->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6489                                 MONO_ADD_INS (cfg->cbb, f2i_new);
6490
6491                                 MONO_INST_NEW (cfg, f2i_cmp, f2i_opcode);
6492                                 f2i_cmp->dreg = mono_alloc_ireg (cfg);
6493                                 f2i_cmp->sreg1 = args [2]->dreg;
6494                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6495                                         f2i_cmp->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6496                                 MONO_ADD_INS (cfg->cbb, f2i_cmp);
6497                         }
6498
6499                         MONO_INST_NEW (cfg, ins, opcode);
6500                         ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
6501                         ins->sreg1 = args [0]->dreg;
6502                         ins->sreg2 = is_float ? f2i_new->dreg : args [1]->dreg;
6503                         ins->sreg3 = is_float ? f2i_cmp->dreg : args [2]->dreg;
6504                         MONO_ADD_INS (cfg->cbb, ins);
6505
6506                         switch (fsig->params [1]->type) {
6507                         case MONO_TYPE_I4:
6508                                 ins->type = STACK_I4;
6509                                 break;
6510                         case MONO_TYPE_I8:
6511                                 ins->type = STACK_I8;
6512                                 break;
6513                         case MONO_TYPE_I:
6514 #if SIZEOF_REGISTER == 8
6515                                 ins->type = STACK_I8;
6516 #else
6517                                 ins->type = STACK_I4;
6518 #endif
6519                                 break;
6520                         case MONO_TYPE_R4:
6521                                 ins->type = cfg->r4_stack_type;
6522                                 break;
6523                         case MONO_TYPE_R8:
6524                                 ins->type = STACK_R8;
6525                                 break;
6526                         default:
6527                                 g_assert (mini_type_is_reference (fsig->params [1]));
6528                                 ins->type = STACK_OBJ;
6529                                 break;
6530                         }
6531
6532                         if (is_float) {
6533                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6534                                 i2f->dreg = mono_alloc_freg (cfg);
6535                                 i2f->sreg1 = ins->dreg;
6536                                 i2f->type = STACK_R8;
6537                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6538                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6539                                 MONO_ADD_INS (cfg->cbb, i2f);
6540
6541                                 ins = i2f;
6542                         }
6543
6544                         if (cfg->gen_write_barriers && is_ref)
6545                                 emit_write_barrier (cfg, args [0], args [1]);
6546                 }
6547                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 4 &&
6548                          fsig->params [1]->type == MONO_TYPE_I4) {
6549                         MonoInst *cmp, *ceq;
6550
6551                         if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I4))
6552                                 return NULL;
6553
6554                         /* int32 r = CAS (location, value, comparand); */
6555                         MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
6556                         ins->dreg = alloc_ireg (cfg);
6557                         ins->sreg1 = args [0]->dreg;
6558                         ins->sreg2 = args [1]->dreg;
6559                         ins->sreg3 = args [2]->dreg;
6560                         ins->type = STACK_I4;
6561                         MONO_ADD_INS (cfg->cbb, ins);
6562
6563                         /* bool result = r == comparand; */
6564                         MONO_INST_NEW (cfg, cmp, OP_ICOMPARE);
6565                         cmp->sreg1 = ins->dreg;
6566                         cmp->sreg2 = args [2]->dreg;
6567                         cmp->type = STACK_I4;
6568                         MONO_ADD_INS (cfg->cbb, cmp);
6569
6570                         MONO_INST_NEW (cfg, ceq, OP_ICEQ);
6571                         ceq->dreg = alloc_ireg (cfg);
6572                         ceq->type = STACK_I4;
6573                         MONO_ADD_INS (cfg->cbb, ceq);
6574
6575                         /* *success = result; */
6576                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, args [3]->dreg, 0, ceq->dreg);
6577
6578                         cfg->has_atomic_cas_i4 = TRUE;
6579                 }
6580                 else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0)
6581                         ins = emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6582
6583                 if (ins)
6584                         return ins;
6585         } else if (cmethod->klass->image == mono_defaults.corlib &&
6586                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6587                            (strcmp (cmethod->klass->name, "Volatile") == 0)) {
6588                 ins = NULL;
6589
6590                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Read") && fsig->param_count == 1) {
6591                         guint32 opcode = 0;
6592                         MonoType *t = fsig->params [0];
6593                         gboolean is_ref;
6594                         gboolean is_float = t->type == MONO_TYPE_R4 || t->type == MONO_TYPE_R8;
6595
6596                         g_assert (t->byref);
6597                         /* t is a byref type, so the reference check is more complicated */
6598                         is_ref = mini_type_is_reference (&mono_class_from_mono_type (t)->byval_arg);
6599                         if (t->type == MONO_TYPE_I1)
6600                                 opcode = OP_ATOMIC_LOAD_I1;
6601                         else if (t->type == MONO_TYPE_U1 || t->type == MONO_TYPE_BOOLEAN)
6602                                 opcode = OP_ATOMIC_LOAD_U1;
6603                         else if (t->type == MONO_TYPE_I2)
6604                                 opcode = OP_ATOMIC_LOAD_I2;
6605                         else if (t->type == MONO_TYPE_U2)
6606                                 opcode = OP_ATOMIC_LOAD_U2;
6607                         else if (t->type == MONO_TYPE_I4)
6608                                 opcode = OP_ATOMIC_LOAD_I4;
6609                         else if (t->type == MONO_TYPE_U4)
6610                                 opcode = OP_ATOMIC_LOAD_U4;
6611                         else if (t->type == MONO_TYPE_R4)
6612                                 opcode = OP_ATOMIC_LOAD_R4;
6613                         else if (t->type == MONO_TYPE_R8)
6614                                 opcode = OP_ATOMIC_LOAD_R8;
6615 #if SIZEOF_REGISTER == 8
6616                         else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_I)
6617                                 opcode = OP_ATOMIC_LOAD_I8;
6618                         else if (is_ref || t->type == MONO_TYPE_U8 || t->type == MONO_TYPE_U)
6619                                 opcode = OP_ATOMIC_LOAD_U8;
6620 #else
6621                         else if (t->type == MONO_TYPE_I)
6622                                 opcode = OP_ATOMIC_LOAD_I4;
6623                         else if (is_ref || t->type == MONO_TYPE_U)
6624                                 opcode = OP_ATOMIC_LOAD_U4;
6625 #endif
6626
6627                         if (opcode) {
6628                                 if (!mono_arch_opcode_supported (opcode))
6629                                         return NULL;
6630
6631                                 MONO_INST_NEW (cfg, ins, opcode);
6632                                 ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : (is_float ? mono_alloc_freg (cfg) : mono_alloc_ireg (cfg));
6633                                 ins->sreg1 = args [0]->dreg;
6634                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_ACQ;
6635                                 MONO_ADD_INS (cfg->cbb, ins);
6636
6637                                 switch (t->type) {
6638                                 case MONO_TYPE_BOOLEAN:
6639                                 case MONO_TYPE_I1:
6640                                 case MONO_TYPE_U1:
6641                                 case MONO_TYPE_I2:
6642                                 case MONO_TYPE_U2:
6643                                 case MONO_TYPE_I4:
6644                                 case MONO_TYPE_U4:
6645                                         ins->type = STACK_I4;
6646                                         break;
6647                                 case MONO_TYPE_I8:
6648                                 case MONO_TYPE_U8:
6649                                         ins->type = STACK_I8;
6650                                         break;
6651                                 case MONO_TYPE_I:
6652                                 case MONO_TYPE_U:
6653 #if SIZEOF_REGISTER == 8
6654                                         ins->type = STACK_I8;
6655 #else
6656                                         ins->type = STACK_I4;
6657 #endif
6658                                         break;
6659                                 case MONO_TYPE_R4:
6660                                         ins->type = cfg->r4_stack_type;
6661                                         break;
6662                                 case MONO_TYPE_R8:
6663                                         ins->type = STACK_R8;
6664                                         break;
6665                                 default:
6666                                         g_assert (is_ref);
6667                                         ins->type = STACK_OBJ;
6668                                         break;
6669                                 }
6670                         }
6671                 }
6672
6673                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Write") && fsig->param_count == 2) {
6674                         guint32 opcode = 0;
6675                         MonoType *t = fsig->params [0];
6676                         gboolean is_ref;
6677
6678                         g_assert (t->byref);
6679                         is_ref = mini_type_is_reference (&mono_class_from_mono_type (t)->byval_arg);
6680                         if (t->type == MONO_TYPE_I1)
6681                                 opcode = OP_ATOMIC_STORE_I1;
6682                         else if (t->type == MONO_TYPE_U1 || t->type == MONO_TYPE_BOOLEAN)
6683                                 opcode = OP_ATOMIC_STORE_U1;
6684                         else if (t->type == MONO_TYPE_I2)
6685                                 opcode = OP_ATOMIC_STORE_I2;
6686                         else if (t->type == MONO_TYPE_U2)
6687                                 opcode = OP_ATOMIC_STORE_U2;
6688                         else if (t->type == MONO_TYPE_I4)
6689                                 opcode = OP_ATOMIC_STORE_I4;
6690                         else if (t->type == MONO_TYPE_U4)
6691                                 opcode = OP_ATOMIC_STORE_U4;
6692                         else if (t->type == MONO_TYPE_R4)
6693                                 opcode = OP_ATOMIC_STORE_R4;
6694                         else if (t->type == MONO_TYPE_R8)
6695                                 opcode = OP_ATOMIC_STORE_R8;
6696 #if SIZEOF_REGISTER == 8
6697                         else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_I)
6698                                 opcode = OP_ATOMIC_STORE_I8;
6699                         else if (is_ref || t->type == MONO_TYPE_U8 || t->type == MONO_TYPE_U)
6700                                 opcode = OP_ATOMIC_STORE_U8;
6701 #else
6702                         else if (t->type == MONO_TYPE_I)
6703                                 opcode = OP_ATOMIC_STORE_I4;
6704                         else if (is_ref || t->type == MONO_TYPE_U)
6705                                 opcode = OP_ATOMIC_STORE_U4;
6706 #endif
6707
6708                         if (opcode) {
6709                                 if (!mono_arch_opcode_supported (opcode))
6710                                         return NULL;
6711
6712                                 MONO_INST_NEW (cfg, ins, opcode);
6713                                 ins->dreg = args [0]->dreg;
6714                                 ins->sreg1 = args [1]->dreg;
6715                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_REL;
6716                                 MONO_ADD_INS (cfg->cbb, ins);
6717
6718                                 if (cfg->gen_write_barriers && is_ref)
6719                                         emit_write_barrier (cfg, args [0], args [1]);
6720                         }
6721                 }
6722
6723                 if (ins)
6724                         return ins;
6725         } else if (cmethod->klass->image == mono_defaults.corlib &&
6726                            (strcmp (cmethod->klass->name_space, "System.Diagnostics") == 0) &&
6727                            (strcmp (cmethod->klass->name, "Debugger") == 0)) {
6728                 if (!strcmp (cmethod->name, "Break") && fsig->param_count == 0) {
6729                         if (should_insert_brekpoint (cfg->method)) {
6730                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
6731                         } else {
6732                                 MONO_INST_NEW (cfg, ins, OP_NOP);
6733                                 MONO_ADD_INS (cfg->cbb, ins);
6734                         }
6735                         return ins;
6736                 }
6737         } else if (cmethod->klass->image == mono_defaults.corlib &&
6738                    (strcmp (cmethod->klass->name_space, "System") == 0) &&
6739                    (strcmp (cmethod->klass->name, "Environment") == 0)) {
6740                 if (!strcmp (cmethod->name, "get_IsRunningOnWindows") && fsig->param_count == 0) {
6741 #ifdef TARGET_WIN32
6742                         EMIT_NEW_ICONST (cfg, ins, 1);
6743 #else
6744                         EMIT_NEW_ICONST (cfg, ins, 0);
6745 #endif
6746                 }
6747         } else if (cmethod->klass->image == mono_defaults.corlib &&
6748                            (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
6749                            (strcmp (cmethod->klass->name, "Assembly") == 0)) {
6750                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetExecutingAssembly")) {
6751                         /* No stack walks are currently available, so implement this as an intrinsic */
6752                         MonoInst *assembly_ins;
6753
6754                         EMIT_NEW_AOTCONST (cfg, assembly_ins, MONO_PATCH_INFO_IMAGE, cfg->method->klass->image);
6755                         ins = mono_emit_jit_icall (cfg, mono_get_assembly_object, &assembly_ins);
6756                         return ins;
6757                 }
6758         } else if (cmethod->klass->image == mono_defaults.corlib &&
6759                            (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
6760                            (strcmp (cmethod->klass->name, "MethodBase") == 0)) {
6761                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetCurrentMethod")) {
6762                         /* No stack walks are currently available, so implement this as an intrinsic */
6763                         MonoInst *method_ins;
6764                         MonoMethod *declaring = cfg->method;
6765
6766                         /* This returns the declaring generic method */
6767                         if (declaring->is_inflated)
6768                                 declaring = ((MonoMethodInflated*)cfg->method)->declaring;
6769                         EMIT_NEW_AOTCONST (cfg, method_ins, MONO_PATCH_INFO_METHODCONST, declaring);
6770                         ins = mono_emit_jit_icall (cfg, mono_get_method_object, &method_ins);
6771                         cfg->no_inline = TRUE;
6772                         if (cfg->method != cfg->current_method)
6773                                 inline_failure (cfg, "MethodBase:GetCurrentMethod ()");
6774                         return ins;
6775                 }
6776         } else if (cmethod->klass == mono_defaults.math_class) {
6777                 /* 
6778                  * There is general branchless code for Min/Max, but it does not work for 
6779                  * all inputs:
6780                  * http://everything2.com/?node_id=1051618
6781                  */
6782         } else if (((!strcmp (cmethod->klass->image->assembly->aname.name, "MonoMac") ||
6783                     !strcmp (cmethod->klass->image->assembly->aname.name, "monotouch")) &&
6784                                 !strcmp (cmethod->klass->name_space, "XamCore.ObjCRuntime") &&
6785                                 !strcmp (cmethod->klass->name, "Selector")) ||
6786                            (!strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.iOS") &&
6787                                 !strcmp (cmethod->klass->name_space, "ObjCRuntime") &&
6788                                 !strcmp (cmethod->klass->name, "Selector"))
6789                            ) {
6790                 if (cfg->backend->have_objc_get_selector &&
6791                         !strcmp (cmethod->name, "GetHandle") && fsig->param_count == 1 &&
6792                     (args [0]->opcode == OP_GOT_ENTRY || args [0]->opcode == OP_AOTCONST) &&
6793                     cfg->compile_aot && !cfg->llvm_only) {
6794                         MonoInst *pi;
6795                         MonoJumpInfoToken *ji;
6796                         MonoString *s;
6797
6798                         // FIXME: llvmonly
6799
6800                         cfg->exception_message = g_strdup ("GetHandle");
6801                         cfg->disable_llvm = TRUE;
6802
6803                         if (args [0]->opcode == OP_GOT_ENTRY) {
6804                                 pi = (MonoInst *)args [0]->inst_p1;
6805                                 g_assert (pi->opcode == OP_PATCH_INFO);
6806                                 g_assert (GPOINTER_TO_INT (pi->inst_p1) == MONO_PATCH_INFO_LDSTR);
6807                                 ji = (MonoJumpInfoToken *)pi->inst_p0;
6808                         } else {
6809                                 g_assert (GPOINTER_TO_INT (args [0]->inst_p1) == MONO_PATCH_INFO_LDSTR);
6810                                 ji = (MonoJumpInfoToken *)args [0]->inst_p0;
6811                         }
6812
6813                         NULLIFY_INS (args [0]);
6814
6815                         // FIXME: Ugly
6816                         s = mono_ldstr (cfg->domain, ji->image, mono_metadata_token_index (ji->token));
6817                         MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
6818                         ins->dreg = mono_alloc_ireg (cfg);
6819                         // FIXME: Leaks
6820                         ins->inst_p0 = mono_string_to_utf8 (s);
6821                         MONO_ADD_INS (cfg->cbb, ins);
6822                         return ins;
6823                 }
6824         }
6825
6826 #ifdef MONO_ARCH_SIMD_INTRINSICS
6827         if (cfg->opt & MONO_OPT_SIMD) {
6828                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
6829                 if (ins)
6830                         return ins;
6831         }
6832 #endif
6833
6834         ins = mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
6835         if (ins)
6836                 return ins;
6837
6838         if (COMPILE_LLVM (cfg)) {
6839                 ins = llvm_emit_inst_for_method (cfg, cmethod, fsig, args);
6840                 if (ins)
6841                         return ins;
6842         }
6843
6844         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
6845 }
6846
6847 /*
6848  * This entry point could be used later for arbitrary method
6849  * redirection.
6850  */
6851 inline static MonoInst*
6852 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
6853                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this_ins)
6854 {
6855         if (method->klass == mono_defaults.string_class) {
6856                 /* managed string allocation support */
6857                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
6858                         MonoInst *iargs [2];
6859                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
6860                         MonoMethod *managed_alloc = NULL;
6861
6862                         g_assert (vtable); /*Should not fail since it System.String*/
6863 #ifndef MONO_CROSS_COMPILE
6864                         managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE, FALSE);
6865 #endif
6866                         if (!managed_alloc)
6867                                 return NULL;
6868                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
6869                         iargs [1] = args [0];
6870                         return mono_emit_method_call (cfg, managed_alloc, iargs, this_ins);
6871                 }
6872         }
6873         return NULL;
6874 }
6875
6876 static void
6877 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
6878 {
6879         MonoInst *store, *temp;
6880         int i;
6881
6882         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
6883                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
6884
6885                 /*
6886                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
6887                  * would be different than the MonoInst's used to represent arguments, and
6888                  * the ldelema implementation can't deal with that.
6889                  * Solution: When ldelema is used on an inline argument, create a var for 
6890                  * it, emit ldelema on that var, and emit the saving code below in
6891                  * inline_method () if needed.
6892                  */
6893                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
6894                 cfg->args [i] = temp;
6895                 /* This uses cfg->args [i] which is set by the preceeding line */
6896                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
6897                 store->cil_code = sp [0]->cil_code;
6898                 sp++;
6899         }
6900 }
6901
6902 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
6903 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
6904
6905 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6906 static gboolean
6907 check_inline_called_method_name_limit (MonoMethod *called_method)
6908 {
6909         int strncmp_result;
6910         static const char *limit = NULL;
6911         
6912         if (limit == NULL) {
6913                 const char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
6914
6915                 if (limit_string != NULL)
6916                         limit = limit_string;
6917                 else
6918                         limit = "";
6919         }
6920
6921         if (limit [0] != '\0') {
6922                 char *called_method_name = mono_method_full_name (called_method, TRUE);
6923
6924                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
6925                 g_free (called_method_name);
6926         
6927                 //return (strncmp_result <= 0);
6928                 return (strncmp_result == 0);
6929         } else {
6930                 return TRUE;
6931         }
6932 }
6933 #endif
6934
6935 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6936 static gboolean
6937 check_inline_caller_method_name_limit (MonoMethod *caller_method)
6938 {
6939         int strncmp_result;
6940         static const char *limit = NULL;
6941         
6942         if (limit == NULL) {
6943                 const char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
6944                 if (limit_string != NULL) {
6945                         limit = limit_string;
6946                 } else {
6947                         limit = "";
6948                 }
6949         }
6950
6951         if (limit [0] != '\0') {
6952                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
6953
6954                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
6955                 g_free (caller_method_name);
6956         
6957                 //return (strncmp_result <= 0);
6958                 return (strncmp_result == 0);
6959         } else {
6960                 return TRUE;
6961         }
6962 }
6963 #endif
6964
6965 static void
6966 emit_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6967 {
6968         static double r8_0 = 0.0;
6969         static float r4_0 = 0.0;
6970         MonoInst *ins;
6971         int t;
6972
6973         rtype = mini_get_underlying_type (rtype);
6974         t = rtype->type;
6975
6976         if (rtype->byref) {
6977                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6978         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6979                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
6980         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6981                 MONO_EMIT_NEW_I8CONST (cfg, dreg, 0);
6982         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6983                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
6984                 ins->type = STACK_R4;
6985                 ins->inst_p0 = (void*)&r4_0;
6986                 ins->dreg = dreg;
6987                 MONO_ADD_INS (cfg->cbb, ins);
6988         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6989                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
6990                 ins->type = STACK_R8;
6991                 ins->inst_p0 = (void*)&r8_0;
6992                 ins->dreg = dreg;
6993                 MONO_ADD_INS (cfg->cbb, ins);
6994         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6995                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6996                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6997         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
6998                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6999         } else {
7000                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
7001         }
7002 }
7003
7004 static void
7005 emit_dummy_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
7006 {
7007         int t;
7008
7009         rtype = mini_get_underlying_type (rtype);
7010         t = rtype->type;
7011
7012         if (rtype->byref) {
7013                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_PCONST);
7014         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
7015                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_ICONST);
7016         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
7017                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_I8CONST);
7018         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
7019                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R4CONST);
7020         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
7021                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R8CONST);
7022         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
7023                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
7024                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
7025         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
7026                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
7027         } else {
7028                 emit_init_rvar (cfg, dreg, rtype);
7029         }
7030 }
7031
7032 /* If INIT is FALSE, emit dummy initialization statements to keep the IR valid */
7033 static void
7034 emit_init_local (MonoCompile *cfg, int local, MonoType *type, gboolean init)
7035 {
7036         MonoInst *var = cfg->locals [local];
7037         if (COMPILE_SOFT_FLOAT (cfg)) {
7038                 MonoInst *store;
7039                 int reg = alloc_dreg (cfg, (MonoStackType)var->type);
7040                 emit_init_rvar (cfg, reg, type);
7041                 EMIT_NEW_LOCSTORE (cfg, store, local, cfg->cbb->last_ins);
7042         } else {
7043                 if (init)
7044                         emit_init_rvar (cfg, var->dreg, type);
7045                 else
7046                         emit_dummy_init_rvar (cfg, var->dreg, type);
7047         }
7048 }
7049
7050 /*
7051  * inline_method:
7052  *
7053  *   Return the cost of inlining CMETHOD.
7054  */
7055 static int
7056 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
7057                            guchar *ip, guint real_offset, gboolean inline_always)
7058 {
7059         MonoError error;
7060         MonoInst *ins, *rvar = NULL;
7061         MonoMethodHeader *cheader;
7062         MonoBasicBlock *ebblock, *sbblock;
7063         int i, costs;
7064         MonoMethod *prev_inlined_method;
7065         MonoInst **prev_locals, **prev_args;
7066         MonoType **prev_arg_types;
7067         guint prev_real_offset;
7068         GHashTable *prev_cbb_hash;
7069         MonoBasicBlock **prev_cil_offset_to_bb;
7070         MonoBasicBlock *prev_cbb;
7071         unsigned char* prev_cil_start;
7072         guint32 prev_cil_offset_to_bb_len;
7073         MonoMethod *prev_current_method;
7074         MonoGenericContext *prev_generic_context;
7075         gboolean ret_var_set, prev_ret_var_set, prev_disable_inline, virtual_ = FALSE;
7076
7077         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
7078
7079 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
7080         if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
7081                 return 0;
7082 #endif
7083 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
7084         if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
7085                 return 0;
7086 #endif
7087
7088         if (!fsig)
7089                 fsig = mono_method_signature (cmethod);
7090
7091         if (cfg->verbose_level > 2)
7092                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
7093
7094         if (!cmethod->inline_info) {
7095                 cfg->stat_inlineable_methods++;
7096                 cmethod->inline_info = 1;
7097         }
7098
7099         /* allocate local variables */
7100         cheader = mono_method_get_header_checked (cmethod, &error);
7101         if (!cheader) {
7102                 if (inline_always) {
7103                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
7104                         mono_error_move (&cfg->error, &error);
7105                 } else {
7106                         mono_error_cleanup (&error);
7107                 }
7108                 return 0;
7109         }
7110
7111         /*Must verify before creating locals as it can cause the JIT to assert.*/
7112         if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
7113                 mono_metadata_free_mh (cheader);
7114                 return 0;
7115         }
7116
7117         /* allocate space to store the return value */
7118         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
7119                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
7120         }
7121
7122         prev_locals = cfg->locals;
7123         cfg->locals = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));
7124         for (i = 0; i < cheader->num_locals; ++i)
7125                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
7126
7127         /* allocate start and end blocks */
7128         /* This is needed so if the inline is aborted, we can clean up */
7129         NEW_BBLOCK (cfg, sbblock);
7130         sbblock->real_offset = real_offset;
7131
7132         NEW_BBLOCK (cfg, ebblock);
7133         ebblock->block_num = cfg->num_bblocks++;
7134         ebblock->real_offset = real_offset;
7135
7136         prev_args = cfg->args;
7137         prev_arg_types = cfg->arg_types;
7138         prev_inlined_method = cfg->inlined_method;
7139         cfg->inlined_method = cmethod;
7140         cfg->ret_var_set = FALSE;
7141         cfg->inline_depth ++;
7142         prev_real_offset = cfg->real_offset;
7143         prev_cbb_hash = cfg->cbb_hash;
7144         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
7145         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
7146         prev_cil_start = cfg->cil_start;
7147         prev_cbb = cfg->cbb;
7148         prev_current_method = cfg->current_method;
7149         prev_generic_context = cfg->generic_context;
7150         prev_ret_var_set = cfg->ret_var_set;
7151         prev_disable_inline = cfg->disable_inline;
7152
7153         if (ip && *ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
7154                 virtual_ = TRUE;
7155
7156         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, sp, real_offset, virtual_);
7157
7158         ret_var_set = cfg->ret_var_set;
7159
7160         cfg->inlined_method = prev_inlined_method;
7161         cfg->real_offset = prev_real_offset;
7162         cfg->cbb_hash = prev_cbb_hash;
7163         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
7164         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
7165         cfg->cil_start = prev_cil_start;
7166         cfg->locals = prev_locals;
7167         cfg->args = prev_args;
7168         cfg->arg_types = prev_arg_types;
7169         cfg->current_method = prev_current_method;
7170         cfg->generic_context = prev_generic_context;
7171         cfg->ret_var_set = prev_ret_var_set;
7172         cfg->disable_inline = prev_disable_inline;
7173         cfg->inline_depth --;
7174
7175         if ((costs >= 0 && costs < 60) || inline_always || (costs >= 0 && (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))) {
7176                 if (cfg->verbose_level > 2)
7177                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
7178                 
7179                 cfg->stat_inlined_methods++;
7180
7181                 /* always add some code to avoid block split failures */
7182                 MONO_INST_NEW (cfg, ins, OP_NOP);
7183                 MONO_ADD_INS (prev_cbb, ins);
7184
7185                 prev_cbb->next_bb = sbblock;
7186                 link_bblock (cfg, prev_cbb, sbblock);
7187
7188                 /* 
7189                  * Get rid of the begin and end bblocks if possible to aid local
7190                  * optimizations.
7191                  */
7192                 mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
7193
7194                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
7195                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
7196
7197                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
7198                         MonoBasicBlock *prev = ebblock->in_bb [0];
7199
7200                         if (prev->next_bb == ebblock) {
7201                                 mono_merge_basic_blocks (cfg, prev, ebblock);
7202                                 cfg->cbb = prev;
7203                                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
7204                                         mono_merge_basic_blocks (cfg, prev_cbb, prev);
7205                                         cfg->cbb = prev_cbb;
7206                                 }
7207                         } else {
7208                                 /* There could be a bblock after 'prev', and making 'prev' the current bb could cause problems */
7209                                 cfg->cbb = ebblock;
7210                         }
7211                 } else {
7212                         /* 
7213                          * Its possible that the rvar is set in some prev bblock, but not in others.
7214                          * (#1835).
7215                          */
7216                         if (rvar) {
7217                                 MonoBasicBlock *bb;
7218
7219                                 for (i = 0; i < ebblock->in_count; ++i) {
7220                                         bb = ebblock->in_bb [i];
7221
7222                                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
7223                                                 cfg->cbb = bb;
7224
7225                                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
7226                                         }
7227                                 }
7228                         }
7229
7230                         cfg->cbb = ebblock;
7231                 }
7232
7233                 if (rvar) {
7234                         /*
7235                          * If the inlined method contains only a throw, then the ret var is not 
7236                          * set, so set it to a dummy value.
7237                          */
7238                         if (!ret_var_set)
7239                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
7240
7241                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
7242                         *sp++ = ins;
7243                 }
7244                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
7245                 return costs + 1;
7246         } else {
7247                 if (cfg->verbose_level > 2)
7248                         printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
7249                 cfg->exception_type = MONO_EXCEPTION_NONE;
7250                 mono_loader_clear_error ();
7251
7252                 /* This gets rid of the newly added bblocks */
7253                 cfg->cbb = prev_cbb;
7254         }
7255         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
7256         return 0;
7257 }
7258
7259 /*
7260  * Some of these comments may well be out-of-date.
7261  * Design decisions: we do a single pass over the IL code (and we do bblock 
7262  * splitting/merging in the few cases when it's required: a back jump to an IL
7263  * address that was not already seen as bblock starting point).
7264  * Code is validated as we go (full verification is still better left to metadata/verify.c).
7265  * Complex operations are decomposed in simpler ones right away. We need to let the 
7266  * arch-specific code peek and poke inside this process somehow (except when the 
7267  * optimizations can take advantage of the full semantic info of coarse opcodes).
7268  * All the opcodes of the form opcode.s are 'normalized' to opcode.
7269  * MonoInst->opcode initially is the IL opcode or some simplification of that 
7270  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
7271  * opcode with value bigger than OP_LAST.
7272  * At this point the IR can be handed over to an interpreter, a dumb code generator
7273  * or to the optimizing code generator that will translate it to SSA form.
7274  *
7275  * Profiling directed optimizations.
7276  * We may compile by default with few or no optimizations and instrument the code
7277  * or the user may indicate what methods to optimize the most either in a config file
7278  * or through repeated runs where the compiler applies offline the optimizations to 
7279  * each method and then decides if it was worth it.
7280  */
7281
7282 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
7283 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
7284 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
7285 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
7286 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
7287 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
7288 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
7289 #define CHECK_TYPELOAD(klass) if (!(klass) || mono_class_has_failure (klass)) TYPE_LOAD_ERROR ((klass))
7290
7291 /* offset from br.s -> br like opcodes */
7292 #define BIG_BRANCH_OFFSET 13
7293
7294 static gboolean
7295 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
7296 {
7297         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
7298
7299         return b == NULL || b == bb;
7300 }
7301
7302 static int
7303 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
7304 {
7305         unsigned char *ip = start;
7306         unsigned char *target;
7307         int i;
7308         guint cli_addr;
7309         MonoBasicBlock *bblock;
7310         const MonoOpcode *opcode;
7311
7312         while (ip < end) {
7313                 cli_addr = ip - start;
7314                 i = mono_opcode_value ((const guint8 **)&ip, end);
7315                 if (i < 0)
7316                         UNVERIFIED;
7317                 opcode = &mono_opcodes [i];
7318                 switch (opcode->argument) {
7319                 case MonoInlineNone:
7320                         ip++; 
7321                         break;
7322                 case MonoInlineString:
7323                 case MonoInlineType:
7324                 case MonoInlineField:
7325                 case MonoInlineMethod:
7326                 case MonoInlineTok:
7327                 case MonoInlineSig:
7328                 case MonoShortInlineR:
7329                 case MonoInlineI:
7330                         ip += 5;
7331                         break;
7332                 case MonoInlineVar:
7333                         ip += 3;
7334                         break;
7335                 case MonoShortInlineVar:
7336                 case MonoShortInlineI:
7337                         ip += 2;
7338                         break;
7339                 case MonoShortInlineBrTarget:
7340                         target = start + cli_addr + 2 + (signed char)ip [1];
7341                         GET_BBLOCK (cfg, bblock, target);
7342                         ip += 2;
7343                         if (ip < end)
7344                                 GET_BBLOCK (cfg, bblock, ip);
7345                         break;
7346                 case MonoInlineBrTarget:
7347                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
7348                         GET_BBLOCK (cfg, bblock, target);
7349                         ip += 5;
7350                         if (ip < end)
7351                                 GET_BBLOCK (cfg, bblock, ip);
7352                         break;
7353                 case MonoInlineSwitch: {
7354                         guint32 n = read32 (ip + 1);
7355                         guint32 j;
7356                         ip += 5;
7357                         cli_addr += 5 + 4 * n;
7358                         target = start + cli_addr;
7359                         GET_BBLOCK (cfg, bblock, target);
7360                         
7361                         for (j = 0; j < n; ++j) {
7362                                 target = start + cli_addr + (gint32)read32 (ip);
7363                                 GET_BBLOCK (cfg, bblock, target);
7364                                 ip += 4;
7365                         }
7366                         break;
7367                 }
7368                 case MonoInlineR:
7369                 case MonoInlineI8:
7370                         ip += 9;
7371                         break;
7372                 default:
7373                         g_assert_not_reached ();
7374                 }
7375
7376                 if (i == CEE_THROW) {
7377                         unsigned char *bb_start = ip - 1;
7378                         
7379                         /* Find the start of the bblock containing the throw */
7380                         bblock = NULL;
7381                         while ((bb_start >= start) && !bblock) {
7382                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
7383                                 bb_start --;
7384                         }
7385                         if (bblock)
7386                                 bblock->out_of_line = 1;
7387                 }
7388         }
7389         return 0;
7390 unverified:
7391 exception_exit:
7392         *pos = ip;
7393         return 1;
7394 }
7395
7396 static inline MonoMethod *
7397 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context, MonoError *error)
7398 {
7399         MonoMethod *method;
7400
7401         mono_error_init (error);
7402
7403         if (m->wrapper_type != MONO_WRAPPER_NONE) {
7404                 method = (MonoMethod *)mono_method_get_wrapper_data (m, token);
7405                 if (context) {
7406                         method = mono_class_inflate_generic_method_checked (method, context, error);
7407                 }
7408         } else {
7409                 method = mono_get_method_checked (m->klass->image, token, klass, context, error);
7410         }
7411
7412         return method;
7413 }
7414
7415 static inline MonoMethod *
7416 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
7417 {
7418         MonoError error;
7419         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context, cfg ? &cfg->error : &error);
7420
7421         if (method && cfg && !cfg->gshared && mono_class_is_open_constructed_type (&method->klass->byval_arg)) {
7422                 mono_error_set_bad_image (&cfg->error, cfg->method->klass->image, "Method with open type while not compiling gshared");
7423                 method = NULL;
7424         }
7425
7426         if (!method && !cfg)
7427                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
7428
7429         return method;
7430 }
7431
7432 static inline MonoClass*
7433 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
7434 {
7435         MonoError error;
7436         MonoClass *klass;
7437
7438         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7439                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
7440                 if (context) {
7441                         klass = mono_class_inflate_generic_class_checked (klass, context, &error);
7442                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7443                 }
7444         } else {
7445                 klass = mono_class_get_and_inflate_typespec_checked (method->klass->image, token, context, &error);
7446                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
7447         }
7448         if (klass)
7449                 mono_class_init (klass);
7450         return klass;
7451 }
7452
7453 static inline MonoMethodSignature*
7454 mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context)
7455 {
7456         MonoMethodSignature *fsig;
7457
7458         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7459                 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
7460         } else {
7461                 fsig = mono_metadata_parse_signature (method->klass->image, token);
7462         }
7463         if (context) {
7464                 MonoError error;
7465                 fsig = mono_inflate_generic_signature(fsig, context, &error);
7466                 // FIXME:
7467                 g_assert(mono_error_ok(&error));
7468         }
7469         return fsig;
7470 }
7471
7472 static MonoMethod*
7473 throw_exception (void)
7474 {
7475         static MonoMethod *method = NULL;
7476
7477         if (!method) {
7478                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
7479                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
7480         }
7481         g_assert (method);
7482         return method;
7483 }
7484
7485 static void
7486 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
7487 {
7488         MonoMethod *thrower = throw_exception ();
7489         MonoInst *args [1];
7490
7491         EMIT_NEW_PCONST (cfg, args [0], ex);
7492         mono_emit_method_call (cfg, thrower, args, NULL);
7493 }
7494
7495 /*
7496  * Return the original method is a wrapper is specified. We can only access 
7497  * the custom attributes from the original method.
7498  */
7499 static MonoMethod*
7500 get_original_method (MonoMethod *method)
7501 {
7502         if (method->wrapper_type == MONO_WRAPPER_NONE)
7503                 return method;
7504
7505         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
7506         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
7507                 return NULL;
7508
7509         /* in other cases we need to find the original method */
7510         return mono_marshal_method_from_wrapper (method);
7511 }
7512
7513 static void
7514 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field)
7515 {
7516         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7517         MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
7518         if (ex)
7519                 emit_throw_exception (cfg, ex);
7520 }
7521
7522 static void
7523 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
7524 {
7525         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7526         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
7527         if (ex)
7528                 emit_throw_exception (cfg, ex);
7529 }
7530
7531 /*
7532  * Check that the IL instructions at ip are the array initialization
7533  * sequence and return the pointer to the data and the size.
7534  */
7535 static const char*
7536 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
7537 {
7538         /*
7539          * newarr[System.Int32]
7540          * dup
7541          * ldtoken field valuetype ...
7542          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
7543          */
7544         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
7545                 MonoError error;
7546                 guint32 token = read32 (ip + 7);
7547                 guint32 field_token = read32 (ip + 2);
7548                 guint32 field_index = field_token & 0xffffff;
7549                 guint32 rva;
7550                 const char *data_ptr;
7551                 int size = 0;
7552                 MonoMethod *cmethod;
7553                 MonoClass *dummy_class;
7554                 MonoClassField *field = mono_field_from_token_checked (method->klass->image, field_token, &dummy_class, NULL, &error);
7555                 int dummy_align;
7556
7557                 if (!field) {
7558                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7559                         return NULL;
7560                 }
7561
7562                 *out_field_token = field_token;
7563
7564                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
7565                 if (!cmethod)
7566                         return NULL;
7567                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
7568                         return NULL;
7569                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
7570                 case MONO_TYPE_BOOLEAN:
7571                 case MONO_TYPE_I1:
7572                 case MONO_TYPE_U1:
7573                         size = 1; break;
7574                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
7575 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
7576                 case MONO_TYPE_CHAR:
7577                 case MONO_TYPE_I2:
7578                 case MONO_TYPE_U2:
7579                         size = 2; break;
7580                 case MONO_TYPE_I4:
7581                 case MONO_TYPE_U4:
7582                 case MONO_TYPE_R4:
7583                         size = 4; break;
7584                 case MONO_TYPE_R8:
7585                 case MONO_TYPE_I8:
7586                 case MONO_TYPE_U8:
7587                         size = 8; break;
7588 #endif
7589                 default:
7590                         return NULL;
7591                 }
7592                 size *= len;
7593                 if (size > mono_type_size (field->type, &dummy_align))
7594                     return NULL;
7595                 *out_size = size;
7596                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
7597                 if (!image_is_dynamic (method->klass->image)) {
7598                         field_index = read32 (ip + 2) & 0xffffff;
7599                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
7600                         data_ptr = mono_image_rva_map (method->klass->image, rva);
7601                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
7602                         /* for aot code we do the lookup on load */
7603                         if (aot && data_ptr)
7604                                 return (const char *)GUINT_TO_POINTER (rva);
7605                 } else {
7606                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
7607                         g_assert (!aot);
7608                         data_ptr = mono_field_get_data (field);
7609                 }
7610                 return data_ptr;
7611         }
7612         return NULL;
7613 }
7614
7615 static void
7616 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
7617 {
7618         MonoError error;
7619         char *method_fname = mono_method_full_name (method, TRUE);
7620         char *method_code;
7621         MonoMethodHeader *header = mono_method_get_header_checked (method, &error);
7622
7623         if (!header) {
7624                 method_code = g_strdup_printf ("could not parse method body due to %s", mono_error_get_message (&error));
7625                 mono_error_cleanup (&error);
7626         } else if (header->code_size == 0)
7627                 method_code = g_strdup ("method body is empty.");
7628         else
7629                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
7630         mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code));
7631         g_free (method_fname);
7632         g_free (method_code);
7633         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
7634 }
7635
7636 static void
7637 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
7638 {
7639         MonoInst *ins;
7640         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
7641         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
7642                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
7643                 /* Optimize reg-reg moves away */
7644                 /* 
7645                  * Can't optimize other opcodes, since sp[0] might point to
7646                  * the last ins of a decomposed opcode.
7647                  */
7648                 sp [0]->dreg = (cfg)->locals [n]->dreg;
7649         } else {
7650                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
7651         }
7652 }
7653
7654 /*
7655  * ldloca inhibits many optimizations so try to get rid of it in common
7656  * cases.
7657  */
7658 static inline unsigned char *
7659 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
7660 {
7661         int local, token;
7662         MonoClass *klass;
7663         MonoType *type;
7664
7665         if (size == 1) {
7666                 local = ip [1];
7667                 ip += 2;
7668         } else {
7669                 local = read16 (ip + 2);
7670                 ip += 4;
7671         }
7672         
7673         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
7674                 /* From the INITOBJ case */
7675                 token = read32 (ip + 2);
7676                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
7677                 CHECK_TYPELOAD (klass);
7678                 type = mini_get_underlying_type (&klass->byval_arg);
7679                 emit_init_local (cfg, local, type, TRUE);
7680                 return ip + 6;
7681         }
7682  exception_exit:
7683         return NULL;
7684 }
7685
7686 static MonoInst*
7687 emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used, MonoInst **sp)
7688 {
7689         MonoInst *icall_args [16];
7690         MonoInst *call_target, *ins, *vtable_ins;
7691         int arg_reg, this_reg, vtable_reg;
7692         gboolean is_iface = cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE;
7693         gboolean is_gsharedvt = cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig);
7694         gboolean variant_iface = FALSE;
7695         guint32 slot;
7696         int offset;
7697
7698         /*
7699          * In llvm-only mode, vtables contain function descriptors instead of
7700          * method addresses/trampolines.
7701          */
7702         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
7703
7704         if (is_iface)
7705                 slot = mono_method_get_imt_slot (cmethod);
7706         else
7707                 slot = mono_method_get_vtable_index (cmethod);
7708
7709         this_reg = sp [0]->dreg;
7710
7711         if (is_iface && mono_class_has_variant_generic_params (cmethod->klass))
7712                 variant_iface = TRUE;
7713
7714         if (!fsig->generic_param_count && !is_iface && !is_gsharedvt) {
7715                 /*
7716                  * The simplest case, a normal virtual call.
7717                  */
7718                 int slot_reg = alloc_preg (cfg);
7719                 int addr_reg = alloc_preg (cfg);
7720                 int arg_reg = alloc_preg (cfg);
7721                 MonoBasicBlock *non_null_bb;
7722
7723                 vtable_reg = alloc_preg (cfg);
7724                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7725                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + (slot * SIZEOF_VOID_P);
7726
7727                 /* Load the vtable slot, which contains a function descriptor. */
7728                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7729
7730                 NEW_BBLOCK (cfg, non_null_bb);
7731
7732                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, slot_reg, 0);
7733                 cfg->cbb->last_ins->flags |= MONO_INST_LIKELY;
7734                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, non_null_bb);
7735
7736                 /* Slow path */
7737                 // FIXME: Make the wrapper use the preserveall cconv
7738                 // FIXME: Use one icall per slot for small slot numbers ?
7739                 icall_args [0] = vtable_ins;
7740                 EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7741                 /* Make the icall return the vtable slot value to save some code space */
7742                 ins = mono_emit_jit_icall (cfg, mono_init_vtable_slot, icall_args);
7743                 ins->dreg = slot_reg;
7744                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, non_null_bb);
7745
7746                 /* Fastpath */
7747                 MONO_START_BB (cfg, non_null_bb);
7748                 /* Load the address + arg from the vtable slot */
7749                 EMIT_NEW_LOAD_MEMBASE (cfg, call_target, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7750                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, arg_reg, slot_reg, SIZEOF_VOID_P);
7751
7752                 return emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
7753         }
7754
7755         if (!fsig->generic_param_count && is_iface && !variant_iface && !is_gsharedvt) {
7756                 /*
7757                  * A simple interface call
7758                  *
7759                  * We make a call through an imt slot to obtain the function descriptor we need to call.
7760                  * The imt slot contains a function descriptor for a runtime function + arg.
7761                  */
7762                 int slot_reg = alloc_preg (cfg);
7763                 int addr_reg = alloc_preg (cfg);
7764                 int arg_reg = alloc_preg (cfg);
7765                 MonoInst *thunk_addr_ins, *thunk_arg_ins, *ftndesc_ins;
7766
7767                 vtable_reg = alloc_preg (cfg);
7768                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7769                 offset = ((gint32)slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
7770
7771                 /*
7772                  * The slot is already initialized when the vtable is created so there is no need
7773                  * to check it here.
7774                  */
7775
7776                 /* Load the imt slot, which contains a function descriptor. */
7777                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7778
7779                 /* Load the address + arg of the imt thunk from the imt slot */
7780                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_addr_ins, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7781                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_arg_ins, OP_LOAD_MEMBASE, arg_reg, slot_reg, SIZEOF_VOID_P);
7782                 /*
7783                  * IMT thunks in llvm-only mode are C functions which take an info argument
7784                  * plus the imt method and return the ftndesc to call.
7785                  */
7786                 icall_args [0] = thunk_arg_ins;
7787                 icall_args [1] = emit_get_rgctx_method (cfg, context_used,
7788                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7789                 ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_thunk, icall_args, thunk_addr_ins, NULL, NULL);
7790
7791                 return emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
7792         }
7793
7794         if ((fsig->generic_param_count || variant_iface) && !is_gsharedvt) {
7795                 /*
7796                  * This is similar to the interface case, the vtable slot points to an imt thunk which is
7797                  * dynamically extended as more instantiations are discovered.
7798                  * This handles generic virtual methods both on classes and interfaces.
7799                  */
7800                 int slot_reg = alloc_preg (cfg);
7801                 int addr_reg = alloc_preg (cfg);
7802                 int arg_reg = alloc_preg (cfg);
7803                 int ftndesc_reg = alloc_preg (cfg);
7804                 MonoInst *thunk_addr_ins, *thunk_arg_ins, *ftndesc_ins;
7805                 MonoBasicBlock *slowpath_bb, *end_bb;
7806
7807                 NEW_BBLOCK (cfg, slowpath_bb);
7808                 NEW_BBLOCK (cfg, end_bb);
7809
7810                 vtable_reg = alloc_preg (cfg);
7811                 EMIT_NEW_LOAD_MEMBASE (cfg, vtable_ins, OP_LOAD_MEMBASE, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
7812                 if (is_iface)
7813                         offset = ((gint32)slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
7814                 else
7815                         offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) + (slot * SIZEOF_VOID_P);
7816
7817                 /* Load the slot, which contains a function descriptor. */
7818                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, slot_reg, vtable_reg, offset);
7819
7820                 /* These slots are not initialized, so fall back to the slow path until they are initialized */
7821                 /* That happens when mono_method_add_generic_virtual_invocation () creates an IMT thunk */
7822                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, slot_reg, 0);
7823                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, slowpath_bb);
7824
7825                 /* Fastpath */
7826                 /* Same as with iface calls */
7827                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_addr_ins, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
7828                 EMIT_NEW_LOAD_MEMBASE (cfg, thunk_arg_ins, OP_LOAD_MEMBASE, arg_reg, slot_reg, SIZEOF_VOID_P);
7829                 icall_args [0] = thunk_arg_ins;
7830                 icall_args [1] = emit_get_rgctx_method (cfg, context_used,
7831                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7832                 ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_thunk, icall_args, thunk_addr_ins, NULL, NULL);
7833                 ftndesc_ins->dreg = ftndesc_reg;
7834                 /*
7835                  * Unlike normal iface calls, these imt thunks can return NULL, i.e. when they are passed an instantiation
7836                  * they don't know about yet. Fall back to the slowpath in that case.
7837                  */
7838                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ftndesc_reg, 0);
7839                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, slowpath_bb);
7840
7841                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
7842
7843                 /* Slowpath */
7844                 MONO_START_BB (cfg, slowpath_bb);
7845                 icall_args [0] = vtable_ins;
7846                 EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7847                 icall_args [2] = emit_get_rgctx_method (cfg, context_used,
7848                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7849                 if (is_iface)
7850                         ftndesc_ins = mono_emit_jit_icall (cfg, mono_resolve_generic_virtual_iface_call, icall_args);
7851                 else
7852                         ftndesc_ins = mono_emit_jit_icall (cfg, mono_resolve_generic_virtual_call, icall_args);
7853                 ftndesc_ins->dreg = ftndesc_reg;
7854                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
7855
7856                 /* Common case */
7857                 MONO_START_BB (cfg, end_bb);
7858                 return emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
7859         }
7860
7861         /*
7862          * Non-optimized cases
7863          */
7864         icall_args [0] = sp [0];
7865         EMIT_NEW_ICONST (cfg, icall_args [1], slot);
7866
7867         icall_args [2] = emit_get_rgctx_method (cfg, context_used,
7868                                                                                         cmethod, MONO_RGCTX_INFO_METHOD);
7869
7870         arg_reg = alloc_preg (cfg);
7871         MONO_EMIT_NEW_PCONST (cfg, arg_reg, NULL);
7872         EMIT_NEW_VARLOADA_VREG (cfg, icall_args [3], arg_reg, &mono_defaults.int_class->byval_arg);
7873
7874         g_assert (is_gsharedvt);
7875         if (is_iface)
7876                 call_target = mono_emit_jit_icall (cfg, mono_resolve_iface_call_gsharedvt, icall_args);
7877         else
7878                 call_target = mono_emit_jit_icall (cfg, mono_resolve_vcall_gsharedvt, icall_args);
7879
7880         /*
7881          * Pass the extra argument even if the callee doesn't receive it, most
7882          * calling conventions allow this.
7883          */
7884         return emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
7885 }
7886
7887 static gboolean
7888 is_exception_class (MonoClass *klass)
7889 {
7890         while (klass) {
7891                 if (klass == mono_defaults.exception_class)
7892                         return TRUE;
7893                 klass = klass->parent;
7894         }
7895         return FALSE;
7896 }
7897
7898 /*
7899  * is_jit_optimizer_disabled:
7900  *
7901  *   Determine whenever M's assembly has a DebuggableAttribute with the
7902  * IsJITOptimizerDisabled flag set.
7903  */
7904 static gboolean
7905 is_jit_optimizer_disabled (MonoMethod *m)
7906 {
7907         MonoError error;
7908         MonoAssembly *ass = m->klass->image->assembly;
7909         MonoCustomAttrInfo* attrs;
7910         MonoClass *klass;
7911         int i;
7912         gboolean val = FALSE;
7913
7914         g_assert (ass);
7915         if (ass->jit_optimizer_disabled_inited)
7916                 return ass->jit_optimizer_disabled;
7917
7918         klass = mono_class_try_get_debuggable_attribute_class ();
7919
7920         if (!klass) {
7921                 /* Linked away */
7922                 ass->jit_optimizer_disabled = FALSE;
7923                 mono_memory_barrier ();
7924                 ass->jit_optimizer_disabled_inited = TRUE;
7925                 return FALSE;
7926         }
7927
7928         attrs = mono_custom_attrs_from_assembly_checked (ass, &error);
7929         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7930         if (attrs) {
7931                 for (i = 0; i < attrs->num_attrs; ++i) {
7932                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
7933                         const gchar *p;
7934                         MonoMethodSignature *sig;
7935
7936                         if (!attr->ctor || attr->ctor->klass != klass)
7937                                 continue;
7938                         /* Decode the attribute. See reflection.c */
7939                         p = (const char*)attr->data;
7940                         g_assert (read16 (p) == 0x0001);
7941                         p += 2;
7942
7943                         // FIXME: Support named parameters
7944                         sig = mono_method_signature (attr->ctor);
7945                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
7946                                 continue;
7947                         /* Two boolean arguments */
7948                         p ++;
7949                         val = *p;
7950                 }
7951                 mono_custom_attrs_free (attrs);
7952         }
7953
7954         ass->jit_optimizer_disabled = val;
7955         mono_memory_barrier ();
7956         ass->jit_optimizer_disabled_inited = TRUE;
7957
7958         return val;
7959 }
7960
7961 static gboolean
7962 is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig, int call_opcode)
7963 {
7964         gboolean supported_tail_call;
7965         int i;
7966
7967         supported_tail_call = mono_arch_tail_call_supported (cfg, mono_method_signature (method), mono_method_signature (cmethod));
7968
7969         for (i = 0; i < fsig->param_count; ++i) {
7970                 if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
7971                         /* These can point to the current method's stack */
7972                         supported_tail_call = FALSE;
7973         }
7974         if (fsig->hasthis && cmethod->klass->valuetype)
7975                 /* this might point to the current method's stack */
7976                 supported_tail_call = FALSE;
7977         if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
7978                 supported_tail_call = FALSE;
7979         if (cfg->method->save_lmf)
7980                 supported_tail_call = FALSE;
7981         if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
7982                 supported_tail_call = FALSE;
7983         if (call_opcode != CEE_CALL)
7984                 supported_tail_call = FALSE;
7985
7986         /* Debugging support */
7987 #if 0
7988         if (supported_tail_call) {
7989                 if (!mono_debug_count ())
7990                         supported_tail_call = FALSE;
7991         }
7992 #endif
7993
7994         return supported_tail_call;
7995 }
7996
7997 /*
7998  * handle_ctor_call:
7999  *
8000  *   Handle calls made to ctors from NEWOBJ opcodes.
8001  */
8002 static void
8003 handle_ctor_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used,
8004                                   MonoInst **sp, guint8 *ip, int *inline_costs)
8005 {
8006         MonoInst *vtable_arg = NULL, *callvirt_this_arg = NULL, *ins;
8007
8008         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
8009                                         mono_method_is_generic_sharable (cmethod, TRUE)) {
8010                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
8011                         mono_class_vtable (cfg->domain, cmethod->klass);
8012                         CHECK_TYPELOAD (cmethod->klass);
8013
8014                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
8015                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
8016                 } else {
8017                         if (context_used) {
8018                                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
8019                                                                                                    cmethod->klass, MONO_RGCTX_INFO_VTABLE);
8020                         } else {
8021                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
8022
8023                                 CHECK_TYPELOAD (cmethod->klass);
8024                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
8025                         }
8026                 }
8027         }
8028
8029         /* Avoid virtual calls to ctors if possible */
8030         if (mono_class_is_marshalbyref (cmethod->klass))
8031                 callvirt_this_arg = sp [0];
8032
8033         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
8034                 g_assert (MONO_TYPE_IS_VOID (fsig->ret));
8035                 CHECK_CFG_EXCEPTION;
8036         } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
8037                            mono_method_check_inlining (cfg, cmethod) &&
8038                            !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE)) {
8039                 int costs;
8040
8041                 if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, FALSE))) {
8042                         cfg->real_offset += 5;
8043
8044                         *inline_costs += costs - 5;
8045                 } else {
8046                         INLINE_FAILURE ("inline failure");
8047                         // FIXME-VT: Clean this up
8048                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
8049                                 GSHAREDVT_FAILURE(*ip);
8050                         mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
8051                 }
8052         } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
8053                 MonoInst *addr;
8054
8055                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
8056
8057                 if (cfg->llvm_only) {
8058                         // FIXME: Avoid initializing vtable_arg
8059                         emit_llvmonly_calli (cfg, fsig, sp, addr);
8060                 } else {
8061                         mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
8062                 }
8063         } else if (context_used &&
8064                            ((!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
8065                                  !mono_class_generic_sharing_enabled (cmethod->klass)) || cfg->gsharedvt)) {
8066                 MonoInst *cmethod_addr;
8067
8068                 /* Generic calls made out of gsharedvt methods cannot be patched, so use an indirect call */
8069
8070                 if (cfg->llvm_only) {
8071                         MonoInst *addr = emit_get_rgctx_method (cfg, context_used, cmethod,
8072                                                                                                         MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
8073                         emit_llvmonly_calli (cfg, fsig, sp, addr);
8074                 } else {
8075                         cmethod_addr = emit_get_rgctx_method (cfg, context_used,
8076                                                                                                   cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
8077
8078                         mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
8079                 }
8080         } else {
8081                 INLINE_FAILURE ("ctor call");
8082                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
8083                                                                                   callvirt_this_arg, NULL, vtable_arg);
8084         }
8085  exception_exit:
8086         return;
8087 }
8088
8089 static void
8090 emit_setret (MonoCompile *cfg, MonoInst *val)
8091 {
8092         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (cfg->method)->ret);
8093         MonoInst *ins;
8094
8095         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
8096                 MonoInst *ret_addr;
8097
8098                 if (!cfg->vret_addr) {
8099                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, val);
8100                 } else {
8101                         EMIT_NEW_RETLOADA (cfg, ret_addr);
8102
8103                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, val->dreg);
8104                         ins->klass = mono_class_from_mono_type (ret_type);
8105                 }
8106         } else {
8107 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
8108                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
8109                         MonoInst *iargs [1];
8110                         MonoInst *conv;
8111
8112                         iargs [0] = val;
8113                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
8114                         mono_arch_emit_setret (cfg, cfg->method, conv);
8115                 } else {
8116                         mono_arch_emit_setret (cfg, cfg->method, val);
8117                 }
8118 #else
8119                 mono_arch_emit_setret (cfg, cfg->method, val);
8120 #endif
8121         }
8122 }
8123
8124 /*
8125  * mono_method_to_ir:
8126  *
8127  *   Translate the .net IL into linear IR.
8128  */
8129 int
8130 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
8131                    MonoInst *return_var, MonoInst **inline_args, 
8132                    guint inline_offset, gboolean is_virtual_call)
8133 {
8134         MonoError error;
8135         MonoInst *ins, **sp, **stack_start;
8136         MonoBasicBlock *tblock = NULL, *init_localsbb = NULL;
8137         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
8138         MonoMethod *cmethod, *method_definition;
8139         MonoInst **arg_array;
8140         MonoMethodHeader *header;
8141         MonoImage *image;
8142         guint32 token, ins_flag;
8143         MonoClass *klass;
8144         MonoClass *constrained_class = NULL;
8145         unsigned char *ip, *end, *target, *err_pos;
8146         MonoMethodSignature *sig;
8147         MonoGenericContext *generic_context = NULL;
8148         MonoGenericContainer *generic_container = NULL;
8149         MonoType **param_types;
8150         int i, n, start_new_bblock, dreg;
8151         int num_calls = 0, inline_costs = 0;
8152         int breakpoint_id = 0;
8153         guint num_args;
8154         GSList *class_inits = NULL;
8155         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
8156         int context_used;
8157         gboolean init_locals, seq_points, skip_dead_blocks;
8158         gboolean sym_seq_points = FALSE;
8159         MonoDebugMethodInfo *minfo;
8160         MonoBitSet *seq_point_locs = NULL;
8161         MonoBitSet *seq_point_set_locs = NULL;
8162
8163         cfg->disable_inline = is_jit_optimizer_disabled (method);
8164
8165         /* serialization and xdomain stuff may need access to private fields and methods */
8166         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
8167         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
8168         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
8169         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
8170         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
8171         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
8172
8173         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
8174         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
8175         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
8176         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
8177         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
8178
8179         image = method->klass->image;
8180         header = mono_method_get_header_checked (method, &cfg->error);
8181         if (!header) {
8182                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
8183                 goto exception_exit;
8184         }
8185         generic_container = mono_method_get_generic_container (method);
8186         sig = mono_method_signature (method);
8187         num_args = sig->hasthis + sig->param_count;
8188         ip = (unsigned char*)header->code;
8189         cfg->cil_start = ip;
8190         end = ip + header->code_size;
8191         cfg->stat_cil_code_size += header->code_size;
8192
8193         seq_points = cfg->gen_seq_points && cfg->method == method;
8194
8195         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
8196                 /* We could hit a seq point before attaching to the JIT (#8338) */
8197                 seq_points = FALSE;
8198         }
8199
8200         if (cfg->gen_sdb_seq_points && cfg->method == method) {
8201                 minfo = mono_debug_lookup_method (method);
8202                 if (minfo) {
8203                         MonoSymSeqPoint *sps;
8204                         int i, n_il_offsets;
8205
8206                         mono_debug_get_seq_points (minfo, NULL, NULL, NULL, &sps, &n_il_offsets);
8207                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
8208                         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);
8209                         sym_seq_points = TRUE;
8210                         for (i = 0; i < n_il_offsets; ++i) {
8211                                 if (sps [i].il_offset < header->code_size)
8212                                         mono_bitset_set_fast (seq_point_locs, sps [i].il_offset);
8213                         }
8214                         g_free (sps);
8215                 } else if (!method->wrapper_type && !method->dynamic && mono_debug_image_has_debug_info (method->klass->image)) {
8216                         /* Methods without line number info like auto-generated property accessors */
8217                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
8218                         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);
8219                         sym_seq_points = TRUE;
8220                 }
8221         }
8222
8223         /* 
8224          * Methods without init_locals set could cause asserts in various passes
8225          * (#497220). To work around this, we emit dummy initialization opcodes
8226          * (OP_DUMMY_ICONST etc.) which generate no code. These are only supported
8227          * on some platforms.
8228          */
8229         if ((cfg->opt & MONO_OPT_UNSAFE) && cfg->backend->have_dummy_init)
8230                 init_locals = header->init_locals;
8231         else
8232                 init_locals = TRUE;
8233
8234         method_definition = method;
8235         while (method_definition->is_inflated) {
8236                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
8237                 method_definition = imethod->declaring;
8238         }
8239
8240         /* SkipVerification is not allowed if core-clr is enabled */
8241         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
8242                 dont_verify = TRUE;
8243                 dont_verify_stloc = TRUE;
8244         }
8245
8246         if (sig->is_inflated)
8247                 generic_context = mono_method_get_context (method);
8248         else if (generic_container)
8249                 generic_context = &generic_container->context;
8250         cfg->generic_context = generic_context;
8251
8252         if (!cfg->gshared)
8253                 g_assert (!sig->has_type_parameters);
8254
8255         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
8256                 g_assert (method->is_inflated);
8257                 g_assert (mono_method_get_context (method)->method_inst);
8258         }
8259         if (method->is_inflated && mono_method_get_context (method)->method_inst)
8260                 g_assert (sig->generic_param_count);
8261
8262         if (cfg->method == method) {
8263                 cfg->real_offset = 0;
8264         } else {
8265                 cfg->real_offset = inline_offset;
8266         }
8267
8268         cfg->cil_offset_to_bb = (MonoBasicBlock **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
8269         cfg->cil_offset_to_bb_len = header->code_size;
8270
8271         cfg->current_method = method;
8272
8273         if (cfg->verbose_level > 2)
8274                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
8275
8276         param_types = (MonoType **)mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
8277         if (sig->hasthis)
8278                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
8279         for (n = 0; n < sig->param_count; ++n)
8280                 param_types [n + sig->hasthis] = sig->params [n];
8281         cfg->arg_types = param_types;
8282
8283         cfg->dont_inline = g_list_prepend (cfg->dont_inline, method);
8284         if (cfg->method == method) {
8285
8286                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
8287                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
8288
8289                 /* ENTRY BLOCK */
8290                 NEW_BBLOCK (cfg, start_bblock);
8291                 cfg->bb_entry = start_bblock;
8292                 start_bblock->cil_code = NULL;
8293                 start_bblock->cil_length = 0;
8294
8295                 /* EXIT BLOCK */
8296                 NEW_BBLOCK (cfg, end_bblock);
8297                 cfg->bb_exit = end_bblock;
8298                 end_bblock->cil_code = NULL;
8299                 end_bblock->cil_length = 0;
8300                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
8301                 g_assert (cfg->num_bblocks == 2);
8302
8303                 arg_array = cfg->args;
8304
8305                 if (header->num_clauses) {
8306                         cfg->spvars = g_hash_table_new (NULL, NULL);
8307                         cfg->exvars = g_hash_table_new (NULL, NULL);
8308                 }
8309                 /* handle exception clauses */
8310                 for (i = 0; i < header->num_clauses; ++i) {
8311                         MonoBasicBlock *try_bb;
8312                         MonoExceptionClause *clause = &header->clauses [i];
8313                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
8314
8315                         try_bb->real_offset = clause->try_offset;
8316                         try_bb->try_start = TRUE;
8317                         try_bb->region = ((i + 1) << 8) | clause->flags;
8318                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
8319                         tblock->real_offset = clause->handler_offset;
8320                         tblock->flags |= BB_EXCEPTION_HANDLER;
8321
8322                         /*
8323                          * Linking the try block with the EH block hinders inlining as we won't be able to 
8324                          * merge the bblocks from inlining and produce an artificial hole for no good reason.
8325                          */
8326                         if (COMPILE_LLVM (cfg))
8327                                 link_bblock (cfg, try_bb, tblock);
8328
8329                         if (*(ip + clause->handler_offset) == CEE_POP)
8330                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
8331
8332                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
8333                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
8334                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
8335                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
8336                                 MONO_ADD_INS (tblock, ins);
8337
8338                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FILTER) {
8339                                         /* finally clauses already have a seq point */
8340                                         /* seq points for filter clauses are emitted below */
8341                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
8342                                         MONO_ADD_INS (tblock, ins);
8343                                 }
8344
8345                                 /* todo: is a fault block unsafe to optimize? */
8346                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
8347                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
8348                         }
8349
8350                         /*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);
8351                           while (p < end) {
8352                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
8353                           }*/
8354                         /* catch and filter blocks get the exception object on the stack */
8355                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
8356                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8357
8358                                 /* mostly like handle_stack_args (), but just sets the input args */
8359                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
8360                                 tblock->in_scount = 1;
8361                                 tblock->in_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
8362                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
8363
8364                                 cfg->cbb = tblock;
8365
8366 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
8367                                 /* The EH code passes in the exception in a register to both JITted and LLVM compiled code */
8368                                 if (!cfg->compile_llvm) {
8369                                         MONO_INST_NEW (cfg, ins, OP_GET_EX_OBJ);
8370                                         ins->dreg = tblock->in_stack [0]->dreg;
8371                                         MONO_ADD_INS (tblock, ins);
8372                                 }
8373 #else
8374                                 MonoInst *dummy_use;
8375
8376                                 /* 
8377                                  * Add a dummy use for the exvar so its liveness info will be
8378                                  * correct.
8379                                  */
8380                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
8381 #endif
8382
8383                                 if (seq_points && clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8384                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
8385                                         MONO_ADD_INS (tblock, ins);
8386                                 }
8387                                 
8388                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8389                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
8390                                         tblock->flags |= BB_EXCEPTION_HANDLER;
8391                                         tblock->real_offset = clause->data.filter_offset;
8392                                         tblock->in_scount = 1;
8393                                         tblock->in_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
8394                                         /* The filter block shares the exvar with the handler block */
8395                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
8396                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
8397                                         MONO_ADD_INS (tblock, ins);
8398                                 }
8399                         }
8400
8401                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
8402                                         clause->data.catch_class &&
8403                                         cfg->gshared &&
8404                                         mono_class_check_context_used (clause->data.catch_class)) {
8405                                 /*
8406                                  * In shared generic code with catch
8407                                  * clauses containing type variables
8408                                  * the exception handling code has to
8409                                  * be able to get to the rgctx.
8410                                  * Therefore we have to make sure that
8411                                  * the vtable/mrgctx argument (for
8412                                  * static or generic methods) or the
8413                                  * "this" argument (for non-static
8414                                  * methods) are live.
8415                                  */
8416                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8417                                                 mini_method_get_context (method)->method_inst ||
8418                                                 method->klass->valuetype) {
8419                                         mono_get_vtable_var (cfg);
8420                                 } else {
8421                                         MonoInst *dummy_use;
8422
8423                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
8424                                 }
8425                         }
8426                 }
8427         } else {
8428                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
8429                 cfg->cbb = start_bblock;
8430                 cfg->args = arg_array;
8431                 mono_save_args (cfg, sig, inline_args);
8432         }
8433
8434         /* FIRST CODE BLOCK */
8435         NEW_BBLOCK (cfg, tblock);
8436         tblock->cil_code = ip;
8437         cfg->cbb = tblock;
8438         cfg->ip = ip;
8439
8440         ADD_BBLOCK (cfg, tblock);
8441
8442         if (cfg->method == method) {
8443                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
8444                 if (breakpoint_id) {
8445                         MONO_INST_NEW (cfg, ins, OP_BREAK);
8446                         MONO_ADD_INS (cfg->cbb, ins);
8447                 }
8448         }
8449
8450         /* we use a separate basic block for the initialization code */
8451         NEW_BBLOCK (cfg, init_localsbb);
8452         cfg->bb_init = init_localsbb;
8453         init_localsbb->real_offset = cfg->real_offset;
8454         start_bblock->next_bb = init_localsbb;
8455         init_localsbb->next_bb = cfg->cbb;
8456         link_bblock (cfg, start_bblock, init_localsbb);
8457         link_bblock (cfg, init_localsbb, cfg->cbb);
8458                 
8459         cfg->cbb = init_localsbb;
8460
8461         if (cfg->gsharedvt && cfg->method == method) {
8462                 MonoGSharedVtMethodInfo *info;
8463                 MonoInst *var, *locals_var;
8464                 int dreg;
8465
8466                 info = (MonoGSharedVtMethodInfo *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
8467                 info->method = cfg->method;
8468                 info->count_entries = 16;
8469                 info->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
8470                 cfg->gsharedvt_info = info;
8471
8472                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8473                 /* prevent it from being register allocated */
8474                 //var->flags |= MONO_INST_VOLATILE;
8475                 cfg->gsharedvt_info_var = var;
8476
8477                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
8478                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
8479
8480                 /* Allocate locals */
8481                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8482                 /* prevent it from being register allocated */
8483                 //locals_var->flags |= MONO_INST_VOLATILE;
8484                 cfg->gsharedvt_locals_var = locals_var;
8485
8486                 dreg = alloc_ireg (cfg);
8487                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
8488
8489                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
8490                 ins->dreg = locals_var->dreg;
8491                 ins->sreg1 = dreg;
8492                 MONO_ADD_INS (cfg->cbb, ins);
8493                 cfg->gsharedvt_locals_var_ins = ins;
8494                 
8495                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
8496                 /*
8497                 if (init_locals)
8498                         ins->flags |= MONO_INST_INIT;
8499                 */
8500         }
8501
8502         if (mono_security_core_clr_enabled ()) {
8503                 /* check if this is native code, e.g. an icall or a p/invoke */
8504                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
8505                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
8506                         if (wrapped) {
8507                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
8508                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
8509
8510                                 /* if this ia a native call then it can only be JITted from platform code */
8511                                 if ((icall || pinvk) && method->klass && method->klass->image) {
8512                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
8513                                                 MonoException *ex = icall ? mono_get_exception_security () : 
8514                                                         mono_get_exception_method_access ();
8515                                                 emit_throw_exception (cfg, ex);
8516                                         }
8517                                 }
8518                         }
8519                 }
8520         }
8521
8522         CHECK_CFG_EXCEPTION;
8523
8524         if (header->code_size == 0)
8525                 UNVERIFIED;
8526
8527         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
8528                 ip = err_pos;
8529                 UNVERIFIED;
8530         }
8531
8532         if (cfg->method == method)
8533                 mono_debug_init_method (cfg, cfg->cbb, breakpoint_id);
8534
8535         for (n = 0; n < header->num_locals; ++n) {
8536                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
8537                         UNVERIFIED;
8538         }
8539         class_inits = NULL;
8540
8541         /* We force the vtable variable here for all shared methods
8542            for the possibility that they might show up in a stack
8543            trace where their exact instantiation is needed. */
8544         if (cfg->gshared && method == cfg->method) {
8545                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8546                                 mini_method_get_context (method)->method_inst ||
8547                                 method->klass->valuetype) {
8548                         mono_get_vtable_var (cfg);
8549                 } else {
8550                         /* FIXME: Is there a better way to do this?
8551                            We need the variable live for the duration
8552                            of the whole method. */
8553                         cfg->args [0]->flags |= MONO_INST_VOLATILE;
8554                 }
8555         }
8556
8557         /* add a check for this != NULL to inlined methods */
8558         if (is_virtual_call) {
8559                 MonoInst *arg_ins;
8560
8561                 NEW_ARGLOAD (cfg, arg_ins, 0);
8562                 MONO_ADD_INS (cfg->cbb, arg_ins);
8563                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
8564         }
8565
8566         skip_dead_blocks = !dont_verify;
8567         if (skip_dead_blocks) {
8568                 original_bb = bb = mono_basic_block_split (method, &cfg->error);
8569                 CHECK_CFG_ERROR;
8570                 g_assert (bb);
8571         }
8572
8573         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
8574         stack_start = sp = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
8575
8576         ins_flag = 0;
8577         start_new_bblock = 0;
8578         while (ip < end) {
8579                 if (cfg->method == method)
8580                         cfg->real_offset = ip - header->code;
8581                 else
8582                         cfg->real_offset = inline_offset;
8583                 cfg->ip = ip;
8584
8585                 context_used = 0;
8586
8587                 if (start_new_bblock) {
8588                         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
8589                         if (start_new_bblock == 2) {
8590                                 g_assert (ip == tblock->cil_code);
8591                         } else {
8592                                 GET_BBLOCK (cfg, tblock, ip);
8593                         }
8594                         cfg->cbb->next_bb = tblock;
8595                         cfg->cbb = tblock;
8596                         start_new_bblock = 0;
8597                         for (i = 0; i < cfg->cbb->in_scount; ++i) {
8598                                 if (cfg->verbose_level > 3)
8599                                         printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8600                                 EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8601                                 *sp++ = ins;
8602                         }
8603                         if (class_inits)
8604                                 g_slist_free (class_inits);
8605                         class_inits = NULL;
8606                 } else {
8607                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != cfg->cbb)) {
8608                                 link_bblock (cfg, cfg->cbb, tblock);
8609                                 if (sp != stack_start) {
8610                                         handle_stack_args (cfg, stack_start, sp - stack_start);
8611                                         sp = stack_start;
8612                                         CHECK_UNVERIFIABLE (cfg);
8613                                 }
8614                                 cfg->cbb->next_bb = tblock;
8615                                 cfg->cbb = tblock;
8616                                 for (i = 0; i < cfg->cbb->in_scount; ++i) {
8617                                         if (cfg->verbose_level > 3)
8618                                                 printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8619                                         EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8620                                         *sp++ = ins;
8621                                 }
8622                                 g_slist_free (class_inits);
8623                                 class_inits = NULL;
8624                         }
8625                 }
8626
8627                 if (skip_dead_blocks) {
8628                         int ip_offset = ip - header->code;
8629
8630                         if (ip_offset == bb->end)
8631                                 bb = bb->next;
8632
8633                         if (bb->dead) {
8634                                 int op_size = mono_opcode_size (ip, end);
8635                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
8636
8637                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
8638
8639                                 if (ip_offset + op_size == bb->end) {
8640                                         MONO_INST_NEW (cfg, ins, OP_NOP);
8641                                         MONO_ADD_INS (cfg->cbb, ins);
8642                                         start_new_bblock = 1;
8643                                 }
8644
8645                                 ip += op_size;
8646                                 continue;
8647                         }
8648                 }
8649                 /*
8650                  * Sequence points are points where the debugger can place a breakpoint.
8651                  * Currently, we generate these automatically at points where the IL
8652                  * stack is empty.
8653                  */
8654                 if (seq_points && ((!sym_seq_points && (sp == stack_start)) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
8655                         /*
8656                          * Make methods interruptable at the beginning, and at the targets of
8657                          * backward branches.
8658                          * Also, do this at the start of every bblock in methods with clauses too,
8659                          * to be able to handle instructions with inprecise control flow like
8660                          * throw/endfinally.
8661                          * Backward branches are handled at the end of method-to-ir ().
8662                          */
8663                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
8664                         gboolean sym_seq_point = sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code);
8665
8666                         /* Avoid sequence points on empty IL like .volatile */
8667                         // FIXME: Enable this
8668                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
8669                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
8670                         if ((sp != stack_start) && !sym_seq_point)
8671                                 ins->flags |= MONO_INST_NONEMPTY_STACK;
8672                         MONO_ADD_INS (cfg->cbb, ins);
8673
8674                         if (sym_seq_points)
8675                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
8676                 }
8677
8678                 cfg->cbb->real_offset = cfg->real_offset;
8679
8680                 if ((cfg->method == method) && cfg->coverage_info) {
8681                         guint32 cil_offset = ip - header->code;
8682                         cfg->coverage_info->data [cil_offset].cil_code = ip;
8683
8684                         /* TODO: Use an increment here */
8685 #if defined(TARGET_X86)
8686                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
8687                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
8688                         ins->inst_imm = 1;
8689                         MONO_ADD_INS (cfg->cbb, ins);
8690 #else
8691                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
8692                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
8693 #endif
8694                 }
8695
8696                 if (cfg->verbose_level > 3)
8697                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
8698
8699                 switch (*ip) {
8700                 case CEE_NOP:
8701                         if (seq_points && !sym_seq_points && sp != stack_start) {
8702                                 /*
8703                                  * The C# compiler uses these nops to notify the JIT that it should
8704                                  * insert seq points.
8705                                  */
8706                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
8707                                 MONO_ADD_INS (cfg->cbb, ins);
8708                         }
8709                         if (cfg->keep_cil_nops)
8710                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
8711                         else
8712                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8713                         ip++;
8714                         MONO_ADD_INS (cfg->cbb, ins);
8715                         break;
8716                 case CEE_BREAK:
8717                         if (should_insert_brekpoint (cfg->method)) {
8718                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
8719                         } else {
8720                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8721                         }
8722                         ip++;
8723                         MONO_ADD_INS (cfg->cbb, ins);
8724                         break;
8725                 case CEE_LDARG_0:
8726                 case CEE_LDARG_1:
8727                 case CEE_LDARG_2:
8728                 case CEE_LDARG_3:
8729                         CHECK_STACK_OVF (1);
8730                         n = (*ip)-CEE_LDARG_0;
8731                         CHECK_ARG (n);
8732                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8733                         ip++;
8734                         *sp++ = ins;
8735                         break;
8736                 case CEE_LDLOC_0:
8737                 case CEE_LDLOC_1:
8738                 case CEE_LDLOC_2:
8739                 case CEE_LDLOC_3:
8740                         CHECK_STACK_OVF (1);
8741                         n = (*ip)-CEE_LDLOC_0;
8742                         CHECK_LOCAL (n);
8743                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8744                         ip++;
8745                         *sp++ = ins;
8746                         break;
8747                 case CEE_STLOC_0:
8748                 case CEE_STLOC_1:
8749                 case CEE_STLOC_2:
8750                 case CEE_STLOC_3: {
8751                         CHECK_STACK (1);
8752                         n = (*ip)-CEE_STLOC_0;
8753                         CHECK_LOCAL (n);
8754                         --sp;
8755                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
8756                                 UNVERIFIED;
8757                         emit_stloc_ir (cfg, sp, header, n);
8758                         ++ip;
8759                         inline_costs += 1;
8760                         break;
8761                         }
8762                 case CEE_LDARG_S:
8763                         CHECK_OPSIZE (2);
8764                         CHECK_STACK_OVF (1);
8765                         n = ip [1];
8766                         CHECK_ARG (n);
8767                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8768                         *sp++ = ins;
8769                         ip += 2;
8770                         break;
8771                 case CEE_LDARGA_S:
8772                         CHECK_OPSIZE (2);
8773                         CHECK_STACK_OVF (1);
8774                         n = ip [1];
8775                         CHECK_ARG (n);
8776                         NEW_ARGLOADA (cfg, ins, n);
8777                         MONO_ADD_INS (cfg->cbb, ins);
8778                         *sp++ = ins;
8779                         ip += 2;
8780                         break;
8781                 case CEE_STARG_S:
8782                         CHECK_OPSIZE (2);
8783                         CHECK_STACK (1);
8784                         --sp;
8785                         n = ip [1];
8786                         CHECK_ARG (n);
8787                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
8788                                 UNVERIFIED;
8789                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
8790                         ip += 2;
8791                         break;
8792                 case CEE_LDLOC_S:
8793                         CHECK_OPSIZE (2);
8794                         CHECK_STACK_OVF (1);
8795                         n = ip [1];
8796                         CHECK_LOCAL (n);
8797                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8798                         *sp++ = ins;
8799                         ip += 2;
8800                         break;
8801                 case CEE_LDLOCA_S: {
8802                         unsigned char *tmp_ip;
8803                         CHECK_OPSIZE (2);
8804                         CHECK_STACK_OVF (1);
8805                         CHECK_LOCAL (ip [1]);
8806
8807                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
8808                                 ip = tmp_ip;
8809                                 inline_costs += 1;
8810                                 break;
8811                         }
8812
8813                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
8814                         *sp++ = ins;
8815                         ip += 2;
8816                         break;
8817                 }
8818                 case CEE_STLOC_S:
8819                         CHECK_OPSIZE (2);
8820                         CHECK_STACK (1);
8821                         --sp;
8822                         CHECK_LOCAL (ip [1]);
8823                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
8824                                 UNVERIFIED;
8825                         emit_stloc_ir (cfg, sp, header, ip [1]);
8826                         ip += 2;
8827                         inline_costs += 1;
8828                         break;
8829                 case CEE_LDNULL:
8830                         CHECK_STACK_OVF (1);
8831                         EMIT_NEW_PCONST (cfg, ins, NULL);
8832                         ins->type = STACK_OBJ;
8833                         ++ip;
8834                         *sp++ = ins;
8835                         break;
8836                 case CEE_LDC_I4_M1:
8837                         CHECK_STACK_OVF (1);
8838                         EMIT_NEW_ICONST (cfg, ins, -1);
8839                         ++ip;
8840                         *sp++ = ins;
8841                         break;
8842                 case CEE_LDC_I4_0:
8843                 case CEE_LDC_I4_1:
8844                 case CEE_LDC_I4_2:
8845                 case CEE_LDC_I4_3:
8846                 case CEE_LDC_I4_4:
8847                 case CEE_LDC_I4_5:
8848                 case CEE_LDC_I4_6:
8849                 case CEE_LDC_I4_7:
8850                 case CEE_LDC_I4_8:
8851                         CHECK_STACK_OVF (1);
8852                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
8853                         ++ip;
8854                         *sp++ = ins;
8855                         break;
8856                 case CEE_LDC_I4_S:
8857                         CHECK_OPSIZE (2);
8858                         CHECK_STACK_OVF (1);
8859                         ++ip;
8860                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
8861                         ++ip;
8862                         *sp++ = ins;
8863                         break;
8864                 case CEE_LDC_I4:
8865                         CHECK_OPSIZE (5);
8866                         CHECK_STACK_OVF (1);
8867                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
8868                         ip += 5;
8869                         *sp++ = ins;
8870                         break;
8871                 case CEE_LDC_I8:
8872                         CHECK_OPSIZE (9);
8873                         CHECK_STACK_OVF (1);
8874                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
8875                         ins->type = STACK_I8;
8876                         ins->dreg = alloc_dreg (cfg, STACK_I8);
8877                         ++ip;
8878                         ins->inst_l = (gint64)read64 (ip);
8879                         MONO_ADD_INS (cfg->cbb, ins);
8880                         ip += 8;
8881                         *sp++ = ins;
8882                         break;
8883                 case CEE_LDC_R4: {
8884                         float *f;
8885                         gboolean use_aotconst = FALSE;
8886
8887 #ifdef TARGET_POWERPC
8888                         /* FIXME: Clean this up */
8889                         if (cfg->compile_aot)
8890                                 use_aotconst = TRUE;
8891 #endif
8892
8893                         /* FIXME: we should really allocate this only late in the compilation process */
8894                         f = (float *)mono_domain_alloc (cfg->domain, sizeof (float));
8895                         CHECK_OPSIZE (5);
8896                         CHECK_STACK_OVF (1);
8897
8898                         if (use_aotconst) {
8899                                 MonoInst *cons;
8900                                 int dreg;
8901
8902                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
8903
8904                                 dreg = alloc_freg (cfg);
8905                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
8906                                 ins->type = cfg->r4_stack_type;
8907                         } else {
8908                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
8909                                 ins->type = cfg->r4_stack_type;
8910                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8911                                 ins->inst_p0 = f;
8912                                 MONO_ADD_INS (cfg->cbb, ins);
8913                         }
8914                         ++ip;
8915                         readr4 (ip, f);
8916                         ip += 4;
8917                         *sp++ = ins;                    
8918                         break;
8919                 }
8920                 case CEE_LDC_R8: {
8921                         double *d;
8922                         gboolean use_aotconst = FALSE;
8923
8924 #ifdef TARGET_POWERPC
8925                         /* FIXME: Clean this up */
8926                         if (cfg->compile_aot)
8927                                 use_aotconst = TRUE;
8928 #endif
8929
8930                         /* FIXME: we should really allocate this only late in the compilation process */
8931                         d = (double *)mono_domain_alloc (cfg->domain, sizeof (double));
8932                         CHECK_OPSIZE (9);
8933                         CHECK_STACK_OVF (1);
8934
8935                         if (use_aotconst) {
8936                                 MonoInst *cons;
8937                                 int dreg;
8938
8939                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
8940
8941                                 dreg = alloc_freg (cfg);
8942                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
8943                                 ins->type = STACK_R8;
8944                         } else {
8945                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
8946                                 ins->type = STACK_R8;
8947                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8948                                 ins->inst_p0 = d;
8949                                 MONO_ADD_INS (cfg->cbb, ins);
8950                         }
8951                         ++ip;
8952                         readr8 (ip, d);
8953                         ip += 8;
8954                         *sp++ = ins;
8955                         break;
8956                 }
8957                 case CEE_DUP: {
8958                         MonoInst *temp, *store;
8959                         CHECK_STACK (1);
8960                         CHECK_STACK_OVF (1);
8961                         sp--;
8962                         ins = *sp;
8963
8964                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
8965                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
8966
8967                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8968                         *sp++ = ins;
8969
8970                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8971                         *sp++ = ins;
8972
8973                         ++ip;
8974                         inline_costs += 2;
8975                         break;
8976                 }
8977                 case CEE_POP:
8978                         CHECK_STACK (1);
8979                         ip++;
8980                         --sp;
8981
8982 #ifdef TARGET_X86
8983                         if (sp [0]->type == STACK_R8)
8984                                 /* we need to pop the value from the x86 FP stack */
8985                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
8986 #endif
8987                         break;
8988                 case CEE_JMP: {
8989                         MonoCallInst *call;
8990                         MonoMethodSignature *fsig;
8991                         int i, n;
8992
8993                         INLINE_FAILURE ("jmp");
8994                         GSHAREDVT_FAILURE (*ip);
8995
8996                         CHECK_OPSIZE (5);
8997                         if (stack_start != sp)
8998                                 UNVERIFIED;
8999                         token = read32 (ip + 1);
9000                         /* FIXME: check the signature matches */
9001                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
9002                         CHECK_CFG_ERROR;
9003  
9004                         if (cfg->gshared && mono_method_check_context_used (cmethod))
9005                                 GENERIC_SHARING_FAILURE (CEE_JMP);
9006
9007                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9008
9009                         fsig = mono_method_signature (cmethod);
9010                         n = fsig->param_count + fsig->hasthis;
9011                         if (cfg->llvm_only) {
9012                                 MonoInst **args;
9013
9014                                 args = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
9015                                 for (i = 0; i < n; ++i)
9016                                         EMIT_NEW_ARGLOAD (cfg, args [i], i);
9017                                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, TRUE, args, NULL, NULL, NULL);
9018                                 /*
9019                                  * The code in mono-basic-block.c treats the rest of the code as dead, but we
9020                                  * have to emit a normal return since llvm expects it.
9021                                  */
9022                                 if (cfg->ret)
9023                                         emit_setret (cfg, ins);
9024                                 MONO_INST_NEW (cfg, ins, OP_BR);
9025                                 ins->inst_target_bb = end_bblock;
9026                                 MONO_ADD_INS (cfg->cbb, ins);
9027                                 link_bblock (cfg, cfg->cbb, end_bblock);
9028                                 ip += 5;
9029                                 break;
9030                         } else if (cfg->backend->have_op_tail_call) {
9031                                 /* Handle tail calls similarly to calls */
9032                                 DISABLE_AOT (cfg);
9033
9034                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
9035                                 call->method = cmethod;
9036                                 call->tail_call = TRUE;
9037                                 call->signature = mono_method_signature (cmethod);
9038                                 call->args = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
9039                                 call->inst.inst_p0 = cmethod;
9040                                 for (i = 0; i < n; ++i)
9041                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
9042
9043                                 mono_arch_emit_call (cfg, call);
9044                                 cfg->param_area = MAX(cfg->param_area, call->stack_usage);
9045                                 MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
9046                         } else {
9047                                 for (i = 0; i < num_args; ++i)
9048                                         /* Prevent arguments from being optimized away */
9049                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
9050
9051                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9052                                 ins = (MonoInst*)call;
9053                                 ins->inst_p0 = cmethod;
9054                                 MONO_ADD_INS (cfg->cbb, ins);
9055                         }
9056
9057                         ip += 5;
9058                         start_new_bblock = 1;
9059                         break;
9060                 }
9061                 case CEE_CALLI: {
9062                         MonoInst *addr;
9063                         MonoMethodSignature *fsig;
9064
9065                         CHECK_OPSIZE (5);
9066                         token = read32 (ip + 1);
9067
9068                         ins = NULL;
9069
9070                         //GSHAREDVT_FAILURE (*ip);
9071                         cmethod = NULL;
9072                         CHECK_STACK (1);
9073                         --sp;
9074                         addr = *sp;
9075                         fsig = mini_get_signature (method, token, generic_context);
9076
9077                         if (method->dynamic && fsig->pinvoke) {
9078                                 MonoInst *args [3];
9079
9080                                 /*
9081                                  * This is a call through a function pointer using a pinvoke
9082                                  * signature. Have to create a wrapper and call that instead.
9083                                  * FIXME: This is very slow, need to create a wrapper at JIT time
9084                                  * instead based on the signature.
9085                                  */
9086                                 EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
9087                                 EMIT_NEW_PCONST (cfg, args [1], fsig);
9088                                 args [2] = addr;
9089                                 addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
9090                         }
9091
9092                         n = fsig->param_count + fsig->hasthis;
9093
9094                         CHECK_STACK (n);
9095
9096                         //g_assert (!virtual_ || fsig->hasthis);
9097
9098                         sp -= n;
9099
9100                         inline_costs += 10 * num_calls++;
9101
9102                         /*
9103                          * Making generic calls out of gsharedvt methods.
9104                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9105                          * patching gshared method addresses into a gsharedvt method.
9106                          */
9107                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
9108                                 /*
9109                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
9110                                  */
9111                                 MonoInst *callee = addr;
9112
9113                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
9114                                         /* Not tested */
9115                                         GSHAREDVT_FAILURE (*ip);
9116
9117                                 if (cfg->llvm_only)
9118                                         // FIXME:
9119                                         GSHAREDVT_FAILURE (*ip);
9120
9121                                 addr = emit_get_rgctx_sig (cfg, context_used,
9122                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
9123                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
9124                                 goto calli_end;
9125                         }
9126
9127                         /* Prevent inlining of methods with indirect calls */
9128                         INLINE_FAILURE ("indirect call");
9129
9130                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
9131                                 MonoJumpInfoType info_type;
9132                                 gpointer info_data;
9133
9134                                 /*
9135                                  * Instead of emitting an indirect call, emit a direct call
9136                                  * with the contents of the aotconst as the patch info.
9137                                  */
9138                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
9139                                         info_type = (MonoJumpInfoType)addr->inst_c1;
9140                                         info_data = addr->inst_p0;
9141                                 } else {
9142                                         info_type = (MonoJumpInfoType)addr->inst_right->inst_c1;
9143                                         info_data = addr->inst_right->inst_left;
9144                                 }
9145
9146                                 if (info_type == MONO_PATCH_INFO_ICALL_ADDR || info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
9147                                         ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
9148                                         NULLIFY_INS (addr);
9149                                         goto calli_end;
9150                                 }
9151                         }
9152                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9153
9154                         calli_end:
9155
9156                         /* End of call, INS should contain the result of the call, if any */
9157
9158                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9159                                 g_assert (ins);
9160                                 *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
9161                         }
9162
9163                         CHECK_CFG_EXCEPTION;
9164
9165                         ip += 5;
9166                         ins_flag = 0;
9167                         constrained_class = NULL;
9168                         break;
9169                 }
9170                 case CEE_CALL:
9171                 case CEE_CALLVIRT: {
9172                         MonoInst *addr = NULL;
9173                         MonoMethodSignature *fsig = NULL;
9174                         int array_rank = 0;
9175                         int virtual_ = *ip == CEE_CALLVIRT;
9176                         gboolean pass_imt_from_rgctx = FALSE;
9177                         MonoInst *imt_arg = NULL;
9178                         MonoInst *keep_this_alive = NULL;
9179                         gboolean pass_vtable = FALSE;
9180                         gboolean pass_mrgctx = FALSE;
9181                         MonoInst *vtable_arg = NULL;
9182                         gboolean check_this = FALSE;
9183                         gboolean supported_tail_call = FALSE;
9184                         gboolean tail_call = FALSE;
9185                         gboolean need_seq_point = FALSE;
9186                         guint32 call_opcode = *ip;
9187                         gboolean emit_widen = TRUE;
9188                         gboolean push_res = TRUE;
9189                         gboolean skip_ret = FALSE;
9190                         gboolean delegate_invoke = FALSE;
9191                         gboolean direct_icall = FALSE;
9192                         gboolean constrained_partial_call = FALSE;
9193                         MonoMethod *cil_method;
9194
9195                         CHECK_OPSIZE (5);
9196                         token = read32 (ip + 1);
9197
9198                         ins = NULL;
9199
9200                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
9201                         CHECK_CFG_ERROR;
9202
9203                         cil_method = cmethod;
9204                                 
9205                         if (constrained_class) {
9206                                 if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
9207                                         if (!mini_is_gsharedvt_klass (constrained_class)) {
9208                                                 g_assert (!cmethod->klass->valuetype);
9209                                                 if (!mini_type_is_reference (&constrained_class->byval_arg))
9210                                                         constrained_partial_call = TRUE;
9211                                         }
9212                                 }
9213
9214                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
9215                                         if (cfg->verbose_level > 2)
9216                                                 printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_class));
9217                                         if (!((constrained_class->byval_arg.type == MONO_TYPE_VAR ||
9218                                                    constrained_class->byval_arg.type == MONO_TYPE_MVAR) &&
9219                                                   cfg->gshared)) {
9220                                                 cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_class, generic_context, &cfg->error);
9221                                                 CHECK_CFG_ERROR;
9222                                         }
9223                                 } else {
9224                                         if (cfg->verbose_level > 2)
9225                                                 printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_class));
9226
9227                                         if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
9228                                                 /* 
9229                                                  * This is needed since get_method_constrained can't find 
9230                                                  * the method in klass representing a type var.
9231                                                  * The type var is guaranteed to be a reference type in this
9232                                                  * case.
9233                                                  */
9234                                                 if (!mini_is_gsharedvt_klass (constrained_class))
9235                                                         g_assert (!cmethod->klass->valuetype);
9236                                         } else {
9237                                                 cmethod = mono_get_method_constrained_checked (image, token, constrained_class, generic_context, &cil_method, &cfg->error);
9238                                                 CHECK_CFG_ERROR;
9239                                         }
9240                                 }
9241                         }
9242                                         
9243                         if (!cmethod || mono_loader_get_last_error ()) {
9244                                 if (mono_loader_get_last_error ()) {
9245                                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
9246                                         mono_error_set_from_loader_error (&cfg->error);
9247                                         CHECK_CFG_ERROR;
9248                                 } else {
9249                                         LOAD_ERROR;
9250                                 }
9251                         }
9252                         if (!dont_verify && !cfg->skip_visibility) {
9253                                 MonoMethod *target_method = cil_method;
9254                                 if (method->is_inflated) {
9255                                         target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context), &cfg->error);
9256                                         CHECK_CFG_ERROR;
9257                                 }
9258                                 if (!mono_method_can_access_method (method_definition, target_method) &&
9259                                         !mono_method_can_access_method (method, cil_method))
9260                                         METHOD_ACCESS_FAILURE (method, cil_method);
9261                         }
9262
9263                         if (mono_security_core_clr_enabled ())
9264                                 ensure_method_is_allowed_to_call_method (cfg, method, cil_method);
9265
9266                         if (!virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
9267                                 /* MS.NET seems to silently convert this to a callvirt */
9268                                 virtual_ = 1;
9269
9270                         {
9271                                 /*
9272                                  * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
9273                                  * converts to a callvirt.
9274                                  *
9275                                  * tests/bug-515884.il is an example of this behavior
9276                                  */
9277                                 const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
9278                                 const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
9279                                 if (!virtual_ && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
9280                                         virtual_ = 1;
9281                         }
9282
9283                         if (!cmethod->klass->inited)
9284                                 if (!mono_class_init (cmethod->klass))
9285                                         TYPE_LOAD_ERROR (cmethod->klass);
9286
9287                         fsig = mono_method_signature (cmethod);
9288                         if (!fsig)
9289                                 LOAD_ERROR;
9290                         if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
9291                                 mini_class_is_system_array (cmethod->klass)) {
9292                                 array_rank = cmethod->klass->rank;
9293                         } else if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && icall_is_direct_callable (cfg, cmethod)) {
9294                                 direct_icall = TRUE;
9295                         } else if (fsig->pinvoke) {
9296                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9297                                 fsig = mono_method_signature (wrapper);
9298                         } else if (constrained_class) {
9299                         } else {
9300                                 fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
9301                                 CHECK_CFG_ERROR;
9302                         }
9303
9304                         if (cfg->llvm_only && !cfg->method->wrapper_type)
9305                                 cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
9306
9307                         /* See code below */
9308                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
9309                                 MonoBasicBlock *tbb;
9310
9311                                 GET_BBLOCK (cfg, tbb, ip + 5);
9312                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9313                                         /*
9314                                          * We want to extend the try block to cover the call, but we can't do it if the
9315                                          * call is made directly since its followed by an exception check.
9316                                          */
9317                                         direct_icall = FALSE;
9318                                 }
9319                         }
9320
9321                         mono_save_token_info (cfg, image, token, cil_method);
9322
9323                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip + 5 - header->code)))
9324                                 need_seq_point = TRUE;
9325
9326                         /* Don't support calls made using type arguments for now */
9327                         /*
9328                           if (cfg->gsharedvt) {
9329                           if (mini_is_gsharedvt_signature (fsig))
9330                           GSHAREDVT_FAILURE (*ip);
9331                           }
9332                         */
9333
9334                         if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
9335                                 g_assert_not_reached ();
9336
9337                         n = fsig->param_count + fsig->hasthis;
9338
9339                         if (!cfg->gshared && cmethod->klass->generic_container)
9340                                 UNVERIFIED;
9341
9342                         if (!cfg->gshared)
9343                                 g_assert (!mono_method_check_context_used (cmethod));
9344
9345                         CHECK_STACK (n);
9346
9347                         //g_assert (!virtual_ || fsig->hasthis);
9348
9349                         sp -= n;
9350
9351                         /*
9352                          * We have the `constrained.' prefix opcode.
9353                          */
9354                         if (constrained_class) {
9355                                 if (mini_is_gsharedvt_klass (constrained_class)) {
9356                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_class->valuetype && cmethod->klass->valuetype) {
9357                                                 /* The 'Own method' case below */
9358                                         } else if (cmethod->klass->image != mono_defaults.corlib && !(cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !cmethod->klass->valuetype) {
9359                                                 /* 'The type parameter is instantiated as a reference type' case below. */
9360                                         } else {
9361                                                 ins = handle_constrained_gsharedvt_call (cfg, cmethod, fsig, sp, constrained_class, &emit_widen);
9362                                                 CHECK_CFG_EXCEPTION;
9363                                                 g_assert (ins);
9364                                                 goto call_end;
9365                                         }
9366                                 }
9367
9368                                 if (constrained_partial_call) {
9369                                         gboolean need_box = TRUE;
9370
9371                                         /*
9372                                          * The receiver is a valuetype, but the exact type is not known at compile time. This means the
9373                                          * called method is not known at compile time either. The called method could end up being
9374                                          * one of the methods on the parent classes (object/valuetype/enum), in which case we need
9375                                          * to box the receiver.
9376                                          * A simple solution would be to box always and make a normal virtual call, but that would
9377                                          * be bad performance wise.
9378                                          */
9379                                         if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE && cmethod->klass->generic_class) {
9380                                                 /*
9381                                                  * The parent classes implement no generic interfaces, so the called method will be a vtype method, so no boxing neccessary.
9382                                                  */
9383                                                 need_box = FALSE;
9384                                         }
9385
9386                                         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)) {
9387                                                 /* The called method is not virtual, i.e. Object:GetType (), the receiver is a vtype, has to box */
9388                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9389                                                 ins->klass = constrained_class;
9390                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9391                                                 CHECK_CFG_EXCEPTION;
9392                                         } else if (need_box) {
9393                                                 MonoInst *box_type;
9394                                                 MonoBasicBlock *is_ref_bb, *end_bb;
9395                                                 MonoInst *nonbox_call;
9396
9397                                                 /*
9398                                                  * Determine at runtime whenever the called method is defined on object/valuetype/enum, and emit a boxing call
9399                                                  * if needed.
9400                                                  * FIXME: It is possible to inline the called method in a lot of cases, i.e. for T_INT,
9401                                                  * the no-box case goes to a method in Int32, while the box case goes to a method in Enum.
9402                                                  */
9403                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
9404
9405                                                 NEW_BBLOCK (cfg, is_ref_bb);
9406                                                 NEW_BBLOCK (cfg, end_bb);
9407
9408                                                 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);
9409                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, box_type->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
9410                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
9411
9412                                                 /* Non-ref case */
9413                                                 nonbox_call = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9414
9415                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9416
9417                                                 /* Ref case */
9418                                                 MONO_START_BB (cfg, is_ref_bb);
9419                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9420                                                 ins->klass = constrained_class;
9421                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9422                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9423
9424                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9425
9426                                                 MONO_START_BB (cfg, end_bb);
9427                                                 cfg->cbb = end_bb;
9428
9429                                                 nonbox_call->dreg = ins->dreg;
9430                                                 goto call_end;
9431                                         } else {
9432                                                 g_assert (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
9433                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
9434                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9435                                                 goto call_end;
9436                                         }
9437                                 } else if (constrained_class->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
9438                                         /*
9439                                          * The type parameter is instantiated as a valuetype,
9440                                          * but that type doesn't override the method we're
9441                                          * calling, so we need to box `this'.
9442                                          */
9443                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9444                                         ins->klass = constrained_class;
9445                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9446                                         CHECK_CFG_EXCEPTION;
9447                                 } else if (!constrained_class->valuetype) {
9448                                         int dreg = alloc_ireg_ref (cfg);
9449
9450                                         /*
9451                                          * The type parameter is instantiated as a reference
9452                                          * type.  We have a managed pointer on the stack, so
9453                                          * we need to dereference it here.
9454                                          */
9455                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
9456                                         ins->type = STACK_OBJ;
9457                                         sp [0] = ins;
9458                                 } else {
9459                                         if (cmethod->klass->valuetype) {
9460                                                 /* Own method */
9461                                         } else {
9462                                                 /* Interface method */
9463                                                 int ioffset, slot;
9464
9465                                                 mono_class_setup_vtable (constrained_class);
9466                                                 CHECK_TYPELOAD (constrained_class);
9467                                                 ioffset = mono_class_interface_offset (constrained_class, cmethod->klass);
9468                                                 if (ioffset == -1)
9469                                                         TYPE_LOAD_ERROR (constrained_class);
9470                                                 slot = mono_method_get_vtable_slot (cmethod);
9471                                                 if (slot == -1)
9472                                                         TYPE_LOAD_ERROR (cmethod->klass);
9473                                                 cmethod = constrained_class->vtable [ioffset + slot];
9474
9475                                                 if (cmethod->klass == mono_defaults.enum_class) {
9476                                                         /* Enum implements some interfaces, so treat this as the first case */
9477                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9478                                                         ins->klass = constrained_class;
9479                                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9480                                                         CHECK_CFG_EXCEPTION;
9481                                                 }
9482                                         }
9483                                         virtual_ = 0;
9484                                 }
9485                                 constrained_class = NULL;
9486                         }
9487
9488                         if (check_call_signature (cfg, fsig, sp))
9489                                 UNVERIFIED;
9490
9491                         if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
9492                                 delegate_invoke = TRUE;
9493
9494                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
9495                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9496                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9497                                         emit_widen = FALSE;
9498                                 }
9499
9500                                 goto call_end;
9501                         }
9502
9503                         /* 
9504                          * If the callee is a shared method, then its static cctor
9505                          * might not get called after the call was patched.
9506                          */
9507                         if (cfg->gshared && cmethod->klass != method->klass && cmethod->klass->generic_class && mono_method_is_generic_sharable (cmethod, TRUE) && mono_class_needs_cctor_run (cmethod->klass, method)) {
9508                                 emit_class_init (cfg, cmethod->klass);
9509                                 CHECK_TYPELOAD (cmethod->klass);
9510                         }
9511
9512                         check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
9513
9514                         if (cfg->gshared) {
9515                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
9516
9517                                 context_used = mini_method_check_context_used (cfg, cmethod);
9518
9519                                 if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9520                                         /* Generic method interface
9521                                            calls are resolved via a
9522                                            helper function and don't
9523                                            need an imt. */
9524                                         if (!cmethod_context || !cmethod_context->method_inst)
9525                                                 pass_imt_from_rgctx = TRUE;
9526                                 }
9527
9528                                 /*
9529                                  * If a shared method calls another
9530                                  * shared method then the caller must
9531                                  * have a generic sharing context
9532                                  * because the magic trampoline
9533                                  * requires it.  FIXME: We shouldn't
9534                                  * have to force the vtable/mrgctx
9535                                  * variable here.  Instead there
9536                                  * should be a flag in the cfg to
9537                                  * request a generic sharing context.
9538                                  */
9539                                 if (context_used &&
9540                                                 ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
9541                                         mono_get_vtable_var (cfg);
9542                         }
9543
9544                         if (pass_vtable) {
9545                                 if (context_used) {
9546                                         vtable_arg = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
9547                                 } else {
9548                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
9549
9550                                         CHECK_TYPELOAD (cmethod->klass);
9551                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
9552                                 }
9553                         }
9554
9555                         if (pass_mrgctx) {
9556                                 g_assert (!vtable_arg);
9557
9558                                 if (!cfg->compile_aot) {
9559                                         /* 
9560                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
9561                                          * for type load errors before.
9562                                          */
9563                                         mono_class_setup_vtable (cmethod->klass);
9564                                         CHECK_TYPELOAD (cmethod->klass);
9565                                 }
9566
9567                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
9568
9569                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
9570                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
9571                                          MONO_METHOD_IS_FINAL (cmethod)) &&
9572                                         !mono_class_is_marshalbyref (cmethod->klass)) {
9573                                         if (virtual_)
9574                                                 check_this = TRUE;
9575                                         virtual_ = 0;
9576                                 }
9577                         }
9578
9579                         if (pass_imt_from_rgctx) {
9580                                 g_assert (!pass_vtable);
9581
9582                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9583                                         cmethod, MONO_RGCTX_INFO_METHOD);
9584                         }
9585
9586                         if (check_this)
9587                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9588
9589                         /* Calling virtual generic methods */
9590                         if (virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) &&
9591                             !(MONO_METHOD_IS_FINAL (cmethod) && 
9592                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
9593                             fsig->generic_param_count && 
9594                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) &&
9595                                 !cfg->llvm_only) {
9596                                 MonoInst *this_temp, *this_arg_temp, *store;
9597                                 MonoInst *iargs [4];
9598
9599                                 g_assert (fsig->is_inflated);
9600
9601                                 /* Prevent inlining of methods that contain indirect calls */
9602                                 INLINE_FAILURE ("virtual generic call");
9603
9604                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
9605                                         GSHAREDVT_FAILURE (*ip);
9606
9607                                 if (cfg->backend->have_generalized_imt_thunk && cfg->backend->gshared_supported && cmethod->wrapper_type == MONO_WRAPPER_NONE) {
9608                                         g_assert (!imt_arg);
9609                                         if (!context_used)
9610                                                 g_assert (cmethod->is_inflated);
9611                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
9612                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
9613                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
9614                                 } else {
9615                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
9616                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
9617                                         MONO_ADD_INS (cfg->cbb, store);
9618
9619                                         /* FIXME: This should be a managed pointer */
9620                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
9621
9622                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
9623                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
9624                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
9625                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
9626                                         addr = mono_emit_jit_icall (cfg,
9627                                                                                                 mono_helper_compile_generic_method, iargs);
9628
9629                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
9630
9631                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9632                                 }
9633
9634                                 goto call_end;
9635                         }
9636
9637                         /*
9638                          * Implement a workaround for the inherent races involved in locking:
9639                          * Monitor.Enter ()
9640                          * try {
9641                          * } finally {
9642                          *    Monitor.Exit ()
9643                          * }
9644                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
9645                          * try block, the Exit () won't be executed, see:
9646                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
9647                          * To work around this, we extend such try blocks to include the last x bytes
9648                          * of the Monitor.Enter () call.
9649                          */
9650                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
9651                                 MonoBasicBlock *tbb;
9652
9653                                 GET_BBLOCK (cfg, tbb, ip + 5);
9654                                 /* 
9655                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
9656                                  * from Monitor.Enter like ArgumentNullException.
9657                                  */
9658                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9659                                         /* Mark this bblock as needing to be extended */
9660                                         tbb->extend_try_block = TRUE;
9661                                 }
9662                         }
9663
9664                         /* Conversion to a JIT intrinsic */
9665                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
9666                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9667                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9668                                         emit_widen = FALSE;
9669                                 }
9670                                 goto call_end;
9671                         }
9672
9673                         /* Inlining */
9674                         if ((cfg->opt & MONO_OPT_INLINE) &&
9675                                 (!virtual_ || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
9676                             mono_method_check_inlining (cfg, cmethod)) {
9677                                 int costs;
9678                                 gboolean always = FALSE;
9679
9680                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
9681                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
9682                                         /* Prevent inlining of methods that call wrappers */
9683                                         INLINE_FAILURE ("wrapper call");
9684                                         cmethod = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
9685                                         always = TRUE;
9686                                 }
9687
9688                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, always);
9689                                 if (costs) {
9690                                         cfg->real_offset += 5;
9691
9692                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9693                                                 /* *sp is already set by inline_method */
9694                                                 sp++;
9695                                                 push_res = FALSE;
9696                                         }
9697
9698                                         inline_costs += costs;
9699
9700                                         goto call_end;
9701                                 }
9702                         }
9703
9704                         /* Tail recursion elimination */
9705                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
9706                                 gboolean has_vtargs = FALSE;
9707                                 int i;
9708
9709                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9710                                 INLINE_FAILURE ("tail call");
9711
9712                                 /* keep it simple */
9713                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
9714                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
9715                                                 has_vtargs = TRUE;
9716                                 }
9717
9718                                 if (!has_vtargs) {
9719                                         for (i = 0; i < n; ++i)
9720                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9721                                         MONO_INST_NEW (cfg, ins, OP_BR);
9722                                         MONO_ADD_INS (cfg->cbb, ins);
9723                                         tblock = start_bblock->out_bb [0];
9724                                         link_bblock (cfg, cfg->cbb, tblock);
9725                                         ins->inst_target_bb = tblock;
9726                                         start_new_bblock = 1;
9727
9728                                         /* skip the CEE_RET, too */
9729                                         if (ip_in_bb (cfg, cfg->cbb, ip + 5))
9730                                                 skip_ret = TRUE;
9731                                         push_res = FALSE;
9732                                         goto call_end;
9733                                 }
9734                         }
9735
9736                         inline_costs += 10 * num_calls++;
9737
9738                         /*
9739                          * Making generic calls out of gsharedvt methods.
9740                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9741                          * patching gshared method addresses into a gsharedvt method.
9742                          */
9743                         if (cfg->gsharedvt && (mini_is_gsharedvt_signature (fsig) || cmethod->is_inflated || cmethod->klass->generic_class) &&
9744                                 !(cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY) &&
9745                                 (!(cfg->llvm_only && virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)))) {
9746                                 MonoRgctxInfoType info_type;
9747
9748                                 if (virtual_) {
9749                                         //if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
9750                                                 //GSHAREDVT_FAILURE (*ip);
9751                                         // disable for possible remoting calls
9752                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
9753                                                 GSHAREDVT_FAILURE (*ip);
9754                                         if (fsig->generic_param_count) {
9755                                                 /* virtual generic call */
9756                                                 g_assert (!imt_arg);
9757                                                 /* Same as the virtual generic case above */
9758                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9759                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9760                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
9761                                                 vtable_arg = NULL;
9762                                         } else if ((cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !imt_arg) {
9763                                                 /* This can happen when we call a fully instantiated iface method */
9764                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9765                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9766                                                 vtable_arg = NULL;
9767                                         }
9768                                 }
9769
9770                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
9771                                         keep_this_alive = sp [0];
9772
9773                                 if (virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
9774                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
9775                                 else
9776                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
9777                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
9778
9779                                 if (cfg->llvm_only) {
9780                                         // FIXME: Avoid initializing vtable_arg
9781                                         ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
9782                                 } else {
9783                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9784                                 }
9785                                 goto call_end;
9786                         }
9787
9788                         /* Generic sharing */
9789
9790                         /*
9791                          * Use this if the callee is gsharedvt sharable too, since
9792                          * at runtime we might find an instantiation so the call cannot
9793                          * be patched (the 'no_patch' code path in mini-trampolines.c).
9794                          */
9795                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
9796                                 (!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
9797                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
9798                                 (!virtual_ || MONO_METHOD_IS_FINAL (cmethod) ||
9799                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
9800                                 INLINE_FAILURE ("gshared");
9801
9802                                 g_assert (cfg->gshared && cmethod);
9803                                 g_assert (!addr);
9804
9805                                 /*
9806                                  * We are compiling a call to a
9807                                  * generic method from shared code,
9808                                  * which means that we have to look up
9809                                  * the method in the rgctx and do an
9810                                  * indirect call.
9811                                  */
9812                                 if (fsig->hasthis)
9813                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9814
9815                                 if (cfg->llvm_only) {
9816                                         if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig))
9817                                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER);
9818                                         else
9819                                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9820                                         // FIXME: Avoid initializing imt_arg/vtable_arg
9821                                         ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
9822                                 } else {
9823                                         addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9824                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9825                                 }
9826                                 goto call_end;
9827                         }
9828
9829                         /* Direct calls to icalls */
9830                         if (direct_icall) {
9831                                 MonoMethod *wrapper;
9832                                 int costs;
9833
9834                                 /* Inline the wrapper */
9835                                 wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9836
9837                                 costs = inline_method (cfg, wrapper, fsig, sp, ip, cfg->real_offset, TRUE);
9838                                 g_assert (costs > 0);
9839                                 cfg->real_offset += 5;
9840
9841                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9842                                         /* *sp is already set by inline_method */
9843                                         sp++;
9844                                         push_res = FALSE;
9845                                 }
9846
9847                                 inline_costs += costs;
9848
9849                                 goto call_end;
9850                         }
9851                                         
9852                         /* Array methods */
9853                         if (array_rank) {
9854                                 MonoInst *addr;
9855
9856                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
9857                                         MonoInst *val = sp [fsig->param_count];
9858
9859                                         if (val->type == STACK_OBJ) {
9860                                                 MonoInst *iargs [2];
9861
9862                                                 iargs [0] = sp [0];
9863                                                 iargs [1] = val;
9864                                                 
9865                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
9866                                         }
9867                                         
9868                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
9869                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
9870                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !(val->opcode == OP_PCONST && val->inst_c0 == 0))
9871                                                 emit_write_barrier (cfg, addr, val);
9872                                         if (cfg->gen_write_barriers && mini_is_gsharedvt_klass (cmethod->klass))
9873                                                 GSHAREDVT_FAILURE (*ip);
9874                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
9875                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9876
9877                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
9878                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
9879                                         if (!cmethod->klass->element_class->valuetype && !readonly)
9880                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
9881                                         CHECK_TYPELOAD (cmethod->klass);
9882                                         
9883                                         readonly = FALSE;
9884                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9885                                         ins = addr;
9886                                 } else {
9887                                         g_assert_not_reached ();
9888                                 }
9889
9890                                 emit_widen = FALSE;
9891                                 goto call_end;
9892                         }
9893
9894                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual_ ? sp [0] : NULL);
9895                         if (ins)
9896                                 goto call_end;
9897
9898                         /* Tail prefix / tail call optimization */
9899
9900                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
9901                         /* FIXME: runtime generic context pointer for jumps? */
9902                         /* FIXME: handle this for generic sharing eventually */
9903                         if ((ins_flag & MONO_INST_TAILCALL) &&
9904                                 !vtable_arg && !cfg->gshared && is_supported_tail_call (cfg, method, cmethod, fsig, call_opcode))
9905                                 supported_tail_call = TRUE;
9906
9907                         if (supported_tail_call) {
9908                                 MonoCallInst *call;
9909
9910                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9911                                 INLINE_FAILURE ("tail call");
9912
9913                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
9914
9915                                 if (cfg->backend->have_op_tail_call) {
9916                                         /* Handle tail calls similarly to normal calls */
9917                                         tail_call = TRUE;
9918                                 } else {
9919                                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9920
9921                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9922                                         call->tail_call = TRUE;
9923                                         call->method = cmethod;
9924                                         call->signature = mono_method_signature (cmethod);
9925
9926                                         /*
9927                                          * We implement tail calls by storing the actual arguments into the 
9928                                          * argument variables, then emitting a CEE_JMP.
9929                                          */
9930                                         for (i = 0; i < n; ++i) {
9931                                                 /* Prevent argument from being register allocated */
9932                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
9933                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9934                                         }
9935                                         ins = (MonoInst*)call;
9936                                         ins->inst_p0 = cmethod;
9937                                         ins->inst_p1 = arg_array [0];
9938                                         MONO_ADD_INS (cfg->cbb, ins);
9939                                         link_bblock (cfg, cfg->cbb, end_bblock);
9940                                         start_new_bblock = 1;
9941
9942                                         // FIXME: Eliminate unreachable epilogs
9943
9944                                         /*
9945                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9946                                          * only reachable from this call.
9947                                          */
9948                                         GET_BBLOCK (cfg, tblock, ip + 5);
9949                                         if (tblock == cfg->cbb || tblock->in_count == 0)
9950                                                 skip_ret = TRUE;
9951                                         push_res = FALSE;
9952
9953                                         goto call_end;
9954                                 }
9955                         }
9956
9957                         /* 
9958                          * Synchronized wrappers.
9959                          * Its hard to determine where to replace a method with its synchronized
9960                          * wrapper without causing an infinite recursion. The current solution is
9961                          * to add the synchronized wrapper in the trampolines, and to
9962                          * change the called method to a dummy wrapper, and resolve that wrapper
9963                          * to the real method in mono_jit_compile_method ().
9964                          */
9965                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
9966                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
9967                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
9968                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
9969                         }
9970
9971                         /*
9972                          * Virtual calls in llvm-only mode.
9973                          */
9974                         if (cfg->llvm_only && virtual_ && cmethod && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
9975                                 ins = emit_llvmonly_virtual_call (cfg, cmethod, fsig, context_used, sp);
9976                                 goto call_end;
9977                         }
9978
9979                         /* Common call */
9980                         INLINE_FAILURE ("call");
9981                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual_ ? sp [0] : NULL,
9982                                                                                           imt_arg, vtable_arg);
9983
9984                         if (tail_call && !cfg->llvm_only) {
9985                                 link_bblock (cfg, cfg->cbb, end_bblock);
9986                                 start_new_bblock = 1;
9987
9988                                 // FIXME: Eliminate unreachable epilogs
9989
9990                                 /*
9991                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9992                                  * only reachable from this call.
9993                                  */
9994                                 GET_BBLOCK (cfg, tblock, ip + 5);
9995                                 if (tblock == cfg->cbb || tblock->in_count == 0)
9996                                         skip_ret = TRUE;
9997                                 push_res = FALSE;
9998                         }
9999
10000                         call_end:
10001
10002                         /* End of call, INS should contain the result of the call, if any */
10003
10004                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
10005                                 g_assert (ins);
10006                                 if (emit_widen)
10007                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
10008                                 else
10009                                         *sp++ = ins;
10010                         }
10011
10012                         if (keep_this_alive) {
10013                                 MonoInst *dummy_use;
10014
10015                                 /* See mono_emit_method_call_full () */
10016                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
10017                         }
10018
10019                         CHECK_CFG_EXCEPTION;
10020
10021                         ip += 5;
10022                         if (skip_ret) {
10023                                 g_assert (*ip == CEE_RET);
10024                                 ip += 1;
10025                         }
10026                         ins_flag = 0;
10027                         constrained_class = NULL;
10028                         if (need_seq_point)
10029                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10030                         break;
10031                 }
10032                 case CEE_RET:
10033                         if (cfg->method != method) {
10034                                 /* return from inlined method */
10035                                 /* 
10036                                  * If in_count == 0, that means the ret is unreachable due to
10037                                  * being preceeded by a throw. In that case, inline_method () will
10038                                  * handle setting the return value 
10039                                  * (test case: test_0_inline_throw ()).
10040                                  */
10041                                 if (return_var && cfg->cbb->in_count) {
10042                                         MonoType *ret_type = mono_method_signature (method)->ret;
10043
10044                                         MonoInst *store;
10045                                         CHECK_STACK (1);
10046                                         --sp;
10047
10048                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
10049                                                 UNVERIFIED;
10050
10051                                         //g_assert (returnvar != -1);
10052                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
10053                                         cfg->ret_var_set = TRUE;
10054                                 } 
10055                         } else {
10056                                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
10057
10058                                 if (cfg->lmf_var && cfg->cbb->in_count && !cfg->llvm_only)
10059                                         emit_pop_lmf (cfg);
10060
10061                                 if (cfg->ret) {
10062                                         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (method)->ret);
10063
10064                                         if (seq_points && !sym_seq_points) {
10065                                                 /* 
10066                                                  * Place a seq point here too even through the IL stack is not
10067                                                  * empty, so a step over on
10068                                                  * call <FOO>
10069                                                  * ret
10070                                                  * will work correctly.
10071                                                  */
10072                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
10073                                                 MONO_ADD_INS (cfg->cbb, ins);
10074                                         }
10075
10076                                         g_assert (!return_var);
10077                                         CHECK_STACK (1);
10078                                         --sp;
10079
10080                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
10081                                                 UNVERIFIED;
10082
10083                                         emit_setret (cfg, *sp);
10084                                 }
10085                         }
10086                         if (sp != stack_start)
10087                                 UNVERIFIED;
10088                         MONO_INST_NEW (cfg, ins, OP_BR);
10089                         ip++;
10090                         ins->inst_target_bb = end_bblock;
10091                         MONO_ADD_INS (cfg->cbb, ins);
10092                         link_bblock (cfg, cfg->cbb, end_bblock);
10093                         start_new_bblock = 1;
10094                         break;
10095                 case CEE_BR_S:
10096                         CHECK_OPSIZE (2);
10097                         MONO_INST_NEW (cfg, ins, OP_BR);
10098                         ip++;
10099                         target = ip + 1 + (signed char)(*ip);
10100                         ++ip;
10101                         GET_BBLOCK (cfg, tblock, target);
10102                         link_bblock (cfg, cfg->cbb, tblock);
10103                         ins->inst_target_bb = tblock;
10104                         if (sp != stack_start) {
10105                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10106                                 sp = stack_start;
10107                                 CHECK_UNVERIFIABLE (cfg);
10108                         }
10109                         MONO_ADD_INS (cfg->cbb, ins);
10110                         start_new_bblock = 1;
10111                         inline_costs += BRANCH_COST;
10112                         break;
10113                 case CEE_BEQ_S:
10114                 case CEE_BGE_S:
10115                 case CEE_BGT_S:
10116                 case CEE_BLE_S:
10117                 case CEE_BLT_S:
10118                 case CEE_BNE_UN_S:
10119                 case CEE_BGE_UN_S:
10120                 case CEE_BGT_UN_S:
10121                 case CEE_BLE_UN_S:
10122                 case CEE_BLT_UN_S:
10123                         CHECK_OPSIZE (2);
10124                         CHECK_STACK (2);
10125                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
10126                         ip++;
10127                         target = ip + 1 + *(signed char*)ip;
10128                         ip++;
10129
10130                         ADD_BINCOND (NULL);
10131
10132                         sp = stack_start;
10133                         inline_costs += BRANCH_COST;
10134                         break;
10135                 case CEE_BR:
10136                         CHECK_OPSIZE (5);
10137                         MONO_INST_NEW (cfg, ins, OP_BR);
10138                         ip++;
10139
10140                         target = ip + 4 + (gint32)read32(ip);
10141                         ip += 4;
10142                         GET_BBLOCK (cfg, tblock, target);
10143                         link_bblock (cfg, cfg->cbb, tblock);
10144                         ins->inst_target_bb = tblock;
10145                         if (sp != stack_start) {
10146                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10147                                 sp = stack_start;
10148                                 CHECK_UNVERIFIABLE (cfg);
10149                         }
10150
10151                         MONO_ADD_INS (cfg->cbb, ins);
10152
10153                         start_new_bblock = 1;
10154                         inline_costs += BRANCH_COST;
10155                         break;
10156                 case CEE_BRFALSE_S:
10157                 case CEE_BRTRUE_S:
10158                 case CEE_BRFALSE:
10159                 case CEE_BRTRUE: {
10160                         MonoInst *cmp;
10161                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
10162                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
10163                         guint32 opsize = is_short ? 1 : 4;
10164
10165                         CHECK_OPSIZE (opsize);
10166                         CHECK_STACK (1);
10167                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
10168                                 UNVERIFIED;
10169                         ip ++;
10170                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
10171                         ip += opsize;
10172
10173                         sp--;
10174
10175                         GET_BBLOCK (cfg, tblock, target);
10176                         link_bblock (cfg, cfg->cbb, tblock);
10177                         GET_BBLOCK (cfg, tblock, ip);
10178                         link_bblock (cfg, cfg->cbb, tblock);
10179
10180                         if (sp != stack_start) {
10181                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10182                                 CHECK_UNVERIFIABLE (cfg);
10183                         }
10184
10185                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
10186                         cmp->sreg1 = sp [0]->dreg;
10187                         type_from_op (cfg, cmp, sp [0], NULL);
10188                         CHECK_TYPE (cmp);
10189
10190 #if SIZEOF_REGISTER == 4
10191                         if (cmp->opcode == OP_LCOMPARE_IMM) {
10192                                 /* Convert it to OP_LCOMPARE */
10193                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
10194                                 ins->type = STACK_I8;
10195                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
10196                                 ins->inst_l = 0;
10197                                 MONO_ADD_INS (cfg->cbb, ins);
10198                                 cmp->opcode = OP_LCOMPARE;
10199                                 cmp->sreg2 = ins->dreg;
10200                         }
10201 #endif
10202                         MONO_ADD_INS (cfg->cbb, cmp);
10203
10204                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
10205                         type_from_op (cfg, ins, sp [0], NULL);
10206                         MONO_ADD_INS (cfg->cbb, ins);
10207                         ins->inst_many_bb = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
10208                         GET_BBLOCK (cfg, tblock, target);
10209                         ins->inst_true_bb = tblock;
10210                         GET_BBLOCK (cfg, tblock, ip);
10211                         ins->inst_false_bb = tblock;
10212                         start_new_bblock = 2;
10213
10214                         sp = stack_start;
10215                         inline_costs += BRANCH_COST;
10216                         break;
10217                 }
10218                 case CEE_BEQ:
10219                 case CEE_BGE:
10220                 case CEE_BGT:
10221                 case CEE_BLE:
10222                 case CEE_BLT:
10223                 case CEE_BNE_UN:
10224                 case CEE_BGE_UN:
10225                 case CEE_BGT_UN:
10226                 case CEE_BLE_UN:
10227                 case CEE_BLT_UN:
10228                         CHECK_OPSIZE (5);
10229                         CHECK_STACK (2);
10230                         MONO_INST_NEW (cfg, ins, *ip);
10231                         ip++;
10232                         target = ip + 4 + (gint32)read32(ip);
10233                         ip += 4;
10234
10235                         ADD_BINCOND (NULL);
10236
10237                         sp = stack_start;
10238                         inline_costs += BRANCH_COST;
10239                         break;
10240                 case CEE_SWITCH: {
10241                         MonoInst *src1;
10242                         MonoBasicBlock **targets;
10243                         MonoBasicBlock *default_bblock;
10244                         MonoJumpInfoBBTable *table;
10245                         int offset_reg = alloc_preg (cfg);
10246                         int target_reg = alloc_preg (cfg);
10247                         int table_reg = alloc_preg (cfg);
10248                         int sum_reg = alloc_preg (cfg);
10249                         gboolean use_op_switch;
10250
10251                         CHECK_OPSIZE (5);
10252                         CHECK_STACK (1);
10253                         n = read32 (ip + 1);
10254                         --sp;
10255                         src1 = sp [0];
10256                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
10257                                 UNVERIFIED;
10258
10259                         ip += 5;
10260                         CHECK_OPSIZE (n * sizeof (guint32));
10261                         target = ip + n * sizeof (guint32);
10262
10263                         GET_BBLOCK (cfg, default_bblock, target);
10264                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
10265
10266                         targets = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
10267                         for (i = 0; i < n; ++i) {
10268                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
10269                                 targets [i] = tblock;
10270                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
10271                                 ip += 4;
10272                         }
10273
10274                         if (sp != stack_start) {
10275                                 /* 
10276                                  * Link the current bb with the targets as well, so handle_stack_args
10277                                  * will set their in_stack correctly.
10278                                  */
10279                                 link_bblock (cfg, cfg->cbb, default_bblock);
10280                                 for (i = 0; i < n; ++i)
10281                                         link_bblock (cfg, cfg->cbb, targets [i]);
10282
10283                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10284                                 sp = stack_start;
10285                                 CHECK_UNVERIFIABLE (cfg);
10286
10287                                 /* Undo the links */
10288                                 mono_unlink_bblock (cfg, cfg->cbb, default_bblock);
10289                                 for (i = 0; i < n; ++i)
10290                                         mono_unlink_bblock (cfg, cfg->cbb, targets [i]);
10291                         }
10292
10293                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
10294                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
10295
10296                         for (i = 0; i < n; ++i)
10297                                 link_bblock (cfg, cfg->cbb, targets [i]);
10298
10299                         table = (MonoJumpInfoBBTable *)mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
10300                         table->table = targets;
10301                         table->table_size = n;
10302
10303                         use_op_switch = FALSE;
10304 #ifdef TARGET_ARM
10305                         /* ARM implements SWITCH statements differently */
10306                         /* FIXME: Make it use the generic implementation */
10307                         if (!cfg->compile_aot)
10308                                 use_op_switch = TRUE;
10309 #endif
10310
10311                         if (COMPILE_LLVM (cfg))
10312                                 use_op_switch = TRUE;
10313
10314                         cfg->cbb->has_jump_table = 1;
10315
10316                         if (use_op_switch) {
10317                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
10318                                 ins->sreg1 = src1->dreg;
10319                                 ins->inst_p0 = table;
10320                                 ins->inst_many_bb = targets;
10321                                 ins->klass = (MonoClass *)GUINT_TO_POINTER (n);
10322                                 MONO_ADD_INS (cfg->cbb, ins);
10323                         } else {
10324                                 if (sizeof (gpointer) == 8)
10325                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
10326                                 else
10327                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
10328
10329 #if SIZEOF_REGISTER == 8
10330                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
10331                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
10332 #endif
10333
10334                                 if (cfg->compile_aot) {
10335                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
10336                                 } else {
10337                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
10338                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
10339                                         ins->inst_p0 = table;
10340                                         ins->dreg = table_reg;
10341                                         MONO_ADD_INS (cfg->cbb, ins);
10342                                 }
10343
10344                                 /* FIXME: Use load_memindex */
10345                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
10346                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
10347                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
10348                         }
10349                         start_new_bblock = 1;
10350                         inline_costs += (BRANCH_COST * 2);
10351                         break;
10352                 }
10353                 case CEE_LDIND_I1:
10354                 case CEE_LDIND_U1:
10355                 case CEE_LDIND_I2:
10356                 case CEE_LDIND_U2:
10357                 case CEE_LDIND_I4:
10358                 case CEE_LDIND_U4:
10359                 case CEE_LDIND_I8:
10360                 case CEE_LDIND_I:
10361                 case CEE_LDIND_R4:
10362                 case CEE_LDIND_R8:
10363                 case CEE_LDIND_REF:
10364                         CHECK_STACK (1);
10365                         --sp;
10366
10367                         switch (*ip) {
10368                         case CEE_LDIND_R4:
10369                         case CEE_LDIND_R8:
10370                                 dreg = alloc_freg (cfg);
10371                                 break;
10372                         case CEE_LDIND_I8:
10373                                 dreg = alloc_lreg (cfg);
10374                                 break;
10375                         case CEE_LDIND_REF:
10376                                 dreg = alloc_ireg_ref (cfg);
10377                                 break;
10378                         default:
10379                                 dreg = alloc_preg (cfg);
10380                         }
10381
10382                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
10383                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
10384                         if (*ip == CEE_LDIND_R4)
10385                                 ins->type = cfg->r4_stack_type;
10386                         ins->flags |= ins_flag;
10387                         MONO_ADD_INS (cfg->cbb, ins);
10388                         *sp++ = ins;
10389                         if (ins_flag & MONO_INST_VOLATILE) {
10390                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10391                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10392                         }
10393                         ins_flag = 0;
10394                         ++ip;
10395                         break;
10396                 case CEE_STIND_REF:
10397                 case CEE_STIND_I1:
10398                 case CEE_STIND_I2:
10399                 case CEE_STIND_I4:
10400                 case CEE_STIND_I8:
10401                 case CEE_STIND_R4:
10402                 case CEE_STIND_R8:
10403                 case CEE_STIND_I:
10404                         CHECK_STACK (2);
10405                         sp -= 2;
10406
10407                         if (ins_flag & MONO_INST_VOLATILE) {
10408                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
10409                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
10410                         }
10411
10412                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
10413                         ins->flags |= ins_flag;
10414                         ins_flag = 0;
10415
10416                         MONO_ADD_INS (cfg->cbb, ins);
10417
10418                         if (cfg->gen_write_barriers && *ip == CEE_STIND_REF && method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER && !((sp [1]->opcode == OP_PCONST) && (sp [1]->inst_p0 == 0)))
10419                                 emit_write_barrier (cfg, sp [0], sp [1]);
10420
10421                         inline_costs += 1;
10422                         ++ip;
10423                         break;
10424
10425                 case CEE_MUL:
10426                         CHECK_STACK (2);
10427
10428                         MONO_INST_NEW (cfg, ins, (*ip));
10429                         sp -= 2;
10430                         ins->sreg1 = sp [0]->dreg;
10431                         ins->sreg2 = sp [1]->dreg;
10432                         type_from_op (cfg, ins, sp [0], sp [1]);
10433                         CHECK_TYPE (ins);
10434                         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type);
10435
10436                         /* Use the immediate opcodes if possible */
10437                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
10438                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
10439                                 if (imm_opcode != -1) {
10440                                         ins->opcode = imm_opcode;
10441                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
10442                                         ins->sreg2 = -1;
10443
10444                                         NULLIFY_INS (sp [1]);
10445                                 }
10446                         }
10447
10448                         MONO_ADD_INS ((cfg)->cbb, (ins));
10449
10450                         *sp++ = mono_decompose_opcode (cfg, ins);
10451                         ip++;
10452                         break;
10453                 case CEE_ADD:
10454                 case CEE_SUB:
10455                 case CEE_DIV:
10456                 case CEE_DIV_UN:
10457                 case CEE_REM:
10458                 case CEE_REM_UN:
10459                 case CEE_AND:
10460                 case CEE_OR:
10461                 case CEE_XOR:
10462                 case CEE_SHL:
10463                 case CEE_SHR:
10464                 case CEE_SHR_UN:
10465                         CHECK_STACK (2);
10466
10467                         MONO_INST_NEW (cfg, ins, (*ip));
10468                         sp -= 2;
10469                         ins->sreg1 = sp [0]->dreg;
10470                         ins->sreg2 = sp [1]->dreg;
10471                         type_from_op (cfg, ins, sp [0], sp [1]);
10472                         CHECK_TYPE (ins);
10473                         add_widen_op (cfg, ins, &sp [0], &sp [1]);
10474                         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type);
10475
10476                         /* FIXME: Pass opcode to is_inst_imm */
10477
10478                         /* Use the immediate opcodes if possible */
10479                         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)) {
10480                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
10481                                 if (imm_opcode != -1) {
10482                                         ins->opcode = imm_opcode;
10483                                         if (sp [1]->opcode == OP_I8CONST) {
10484 #if SIZEOF_REGISTER == 8
10485                                                 ins->inst_imm = sp [1]->inst_l;
10486 #else
10487                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
10488                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
10489 #endif
10490                                         }
10491                                         else
10492                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
10493                                         ins->sreg2 = -1;
10494
10495                                         /* Might be followed by an instruction added by add_widen_op */
10496                                         if (sp [1]->next == NULL)
10497                                                 NULLIFY_INS (sp [1]);
10498                                 }
10499                         }
10500                         MONO_ADD_INS ((cfg)->cbb, (ins));
10501
10502                         *sp++ = mono_decompose_opcode (cfg, ins);
10503                         ip++;
10504                         break;
10505                 case CEE_NEG:
10506                 case CEE_NOT:
10507                 case CEE_CONV_I1:
10508                 case CEE_CONV_I2:
10509                 case CEE_CONV_I4:
10510                 case CEE_CONV_R4:
10511                 case CEE_CONV_R8:
10512                 case CEE_CONV_U4:
10513                 case CEE_CONV_I8:
10514                 case CEE_CONV_U8:
10515                 case CEE_CONV_OVF_I8:
10516                 case CEE_CONV_OVF_U8:
10517                 case CEE_CONV_R_UN:
10518                         CHECK_STACK (1);
10519
10520                         /* Special case this earlier so we have long constants in the IR */
10521                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
10522                                 int data = sp [-1]->inst_c0;
10523                                 sp [-1]->opcode = OP_I8CONST;
10524                                 sp [-1]->type = STACK_I8;
10525 #if SIZEOF_REGISTER == 8
10526                                 if ((*ip) == CEE_CONV_U8)
10527                                         sp [-1]->inst_c0 = (guint32)data;
10528                                 else
10529                                         sp [-1]->inst_c0 = data;
10530 #else
10531                                 sp [-1]->inst_ls_word = data;
10532                                 if ((*ip) == CEE_CONV_U8)
10533                                         sp [-1]->inst_ms_word = 0;
10534                                 else
10535                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
10536 #endif
10537                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
10538                         }
10539                         else {
10540                                 ADD_UNOP (*ip);
10541                         }
10542                         ip++;
10543                         break;
10544                 case CEE_CONV_OVF_I4:
10545                 case CEE_CONV_OVF_I1:
10546                 case CEE_CONV_OVF_I2:
10547                 case CEE_CONV_OVF_I:
10548                 case CEE_CONV_OVF_U:
10549                         CHECK_STACK (1);
10550
10551                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10552                                 ADD_UNOP (CEE_CONV_OVF_I8);
10553                                 ADD_UNOP (*ip);
10554                         } else {
10555                                 ADD_UNOP (*ip);
10556                         }
10557                         ip++;
10558                         break;
10559                 case CEE_CONV_OVF_U1:
10560                 case CEE_CONV_OVF_U2:
10561                 case CEE_CONV_OVF_U4:
10562                         CHECK_STACK (1);
10563
10564                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10565                                 ADD_UNOP (CEE_CONV_OVF_U8);
10566                                 ADD_UNOP (*ip);
10567                         } else {
10568                                 ADD_UNOP (*ip);
10569                         }
10570                         ip++;
10571                         break;
10572                 case CEE_CONV_OVF_I1_UN:
10573                 case CEE_CONV_OVF_I2_UN:
10574                 case CEE_CONV_OVF_I4_UN:
10575                 case CEE_CONV_OVF_I8_UN:
10576                 case CEE_CONV_OVF_U1_UN:
10577                 case CEE_CONV_OVF_U2_UN:
10578                 case CEE_CONV_OVF_U4_UN:
10579                 case CEE_CONV_OVF_U8_UN:
10580                 case CEE_CONV_OVF_I_UN:
10581                 case CEE_CONV_OVF_U_UN:
10582                 case CEE_CONV_U2:
10583                 case CEE_CONV_U1:
10584                 case CEE_CONV_I:
10585                 case CEE_CONV_U:
10586                         CHECK_STACK (1);
10587                         ADD_UNOP (*ip);
10588                         CHECK_CFG_EXCEPTION;
10589                         ip++;
10590                         break;
10591                 case CEE_ADD_OVF:
10592                 case CEE_ADD_OVF_UN:
10593                 case CEE_MUL_OVF:
10594                 case CEE_MUL_OVF_UN:
10595                 case CEE_SUB_OVF:
10596                 case CEE_SUB_OVF_UN:
10597                         CHECK_STACK (2);
10598                         ADD_BINOP (*ip);
10599                         ip++;
10600                         break;
10601                 case CEE_CPOBJ:
10602                         GSHAREDVT_FAILURE (*ip);
10603                         CHECK_OPSIZE (5);
10604                         CHECK_STACK (2);
10605                         token = read32 (ip + 1);
10606                         klass = mini_get_class (method, token, generic_context);
10607                         CHECK_TYPELOAD (klass);
10608                         sp -= 2;
10609                         if (generic_class_is_reference_type (cfg, klass)) {
10610                                 MonoInst *store, *load;
10611                                 int dreg = alloc_ireg_ref (cfg);
10612
10613                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
10614                                 load->flags |= ins_flag;
10615                                 MONO_ADD_INS (cfg->cbb, load);
10616
10617                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
10618                                 store->flags |= ins_flag;
10619                                 MONO_ADD_INS (cfg->cbb, store);
10620
10621                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
10622                                         emit_write_barrier (cfg, sp [0], sp [1]);
10623                         } else {
10624                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10625                         }
10626                         ins_flag = 0;
10627                         ip += 5;
10628                         break;
10629                 case CEE_LDOBJ: {
10630                         int loc_index = -1;
10631                         int stloc_len = 0;
10632
10633                         CHECK_OPSIZE (5);
10634                         CHECK_STACK (1);
10635                         --sp;
10636                         token = read32 (ip + 1);
10637                         klass = mini_get_class (method, token, generic_context);
10638                         CHECK_TYPELOAD (klass);
10639
10640                         /* Optimize the common ldobj+stloc combination */
10641                         switch (ip [5]) {
10642                         case CEE_STLOC_S:
10643                                 loc_index = ip [6];
10644                                 stloc_len = 2;
10645                                 break;
10646                         case CEE_STLOC_0:
10647                         case CEE_STLOC_1:
10648                         case CEE_STLOC_2:
10649                         case CEE_STLOC_3:
10650                                 loc_index = ip [5] - CEE_STLOC_0;
10651                                 stloc_len = 1;
10652                                 break;
10653                         default:
10654                                 break;
10655                         }
10656
10657                         if ((loc_index != -1) && ip_in_bb (cfg, cfg->cbb, ip + 5)) {
10658                                 CHECK_LOCAL (loc_index);
10659
10660                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10661                                 ins->dreg = cfg->locals [loc_index]->dreg;
10662                                 ins->flags |= ins_flag;
10663                                 ip += 5;
10664                                 ip += stloc_len;
10665                                 if (ins_flag & MONO_INST_VOLATILE) {
10666                                         /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10667                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10668                                 }
10669                                 ins_flag = 0;
10670                                 break;
10671                         }
10672
10673                         /* Optimize the ldobj+stobj combination */
10674                         /* The reference case ends up being a load+store anyway */
10675                         /* Skip this if the operation is volatile. */
10676                         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)) {
10677                                 CHECK_STACK (1);
10678
10679                                 sp --;
10680
10681                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10682
10683                                 ip += 5 + 5;
10684                                 ins_flag = 0;
10685                                 break;
10686                         }
10687
10688                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10689                         ins->flags |= ins_flag;
10690                         *sp++ = ins;
10691
10692                         if (ins_flag & MONO_INST_VOLATILE) {
10693                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10694                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10695                         }
10696
10697                         ip += 5;
10698                         ins_flag = 0;
10699                         inline_costs += 1;
10700                         break;
10701                 }
10702                 case CEE_LDSTR:
10703                         CHECK_STACK_OVF (1);
10704                         CHECK_OPSIZE (5);
10705                         n = read32 (ip + 1);
10706
10707                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
10708                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
10709                                 ins->type = STACK_OBJ;
10710                                 *sp = ins;
10711                         }
10712                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
10713                                 MonoInst *iargs [1];
10714                                 char *str = (char *)mono_method_get_wrapper_data (method, n);
10715
10716                                 if (cfg->compile_aot)
10717                                         EMIT_NEW_LDSTRLITCONST (cfg, iargs [0], str);
10718                                 else
10719                                         EMIT_NEW_PCONST (cfg, iargs [0], str);
10720                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
10721                         } else {
10722                                 if (cfg->opt & MONO_OPT_SHARED) {
10723                                         MonoInst *iargs [3];
10724
10725                                         if (cfg->compile_aot) {
10726                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
10727                                         }
10728                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10729                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
10730                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
10731                                         *sp = mono_emit_jit_icall (cfg, mono_ldstr, iargs);
10732                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10733                                 } else {
10734                                         if (cfg->cbb->out_of_line) {
10735                                                 MonoInst *iargs [2];
10736
10737                                                 if (image == mono_defaults.corlib) {
10738                                                         /* 
10739                                                          * Avoid relocations in AOT and save some space by using a 
10740                                                          * version of helper_ldstr specialized to mscorlib.
10741                                                          */
10742                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
10743                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
10744                                                 } else {
10745                                                         /* Avoid creating the string object */
10746                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
10747                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
10748                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
10749                                                 }
10750                                         } 
10751                                         else
10752                                         if (cfg->compile_aot) {
10753                                                 NEW_LDSTRCONST (cfg, ins, image, n);
10754                                                 *sp = ins;
10755                                                 MONO_ADD_INS (cfg->cbb, ins);
10756                                         } 
10757                                         else {
10758                                                 NEW_PCONST (cfg, ins, NULL);
10759                                                 ins->type = STACK_OBJ;
10760                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10761                                                 if (!ins->inst_p0)
10762                                                         OUT_OF_MEMORY_FAILURE;
10763
10764                                                 *sp = ins;
10765                                                 MONO_ADD_INS (cfg->cbb, ins);
10766                                         }
10767                                 }
10768                         }
10769
10770                         sp++;
10771                         ip += 5;
10772                         break;
10773                 case CEE_NEWOBJ: {
10774                         MonoInst *iargs [2];
10775                         MonoMethodSignature *fsig;
10776                         MonoInst this_ins;
10777                         MonoInst *alloc;
10778                         MonoInst *vtable_arg = NULL;
10779
10780                         CHECK_OPSIZE (5);
10781                         token = read32 (ip + 1);
10782                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
10783                         CHECK_CFG_ERROR;
10784
10785                         fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
10786                         CHECK_CFG_ERROR;
10787
10788                         mono_save_token_info (cfg, image, token, cmethod);
10789
10790                         if (!mono_class_init (cmethod->klass))
10791                                 TYPE_LOAD_ERROR (cmethod->klass);
10792
10793                         context_used = mini_method_check_context_used (cfg, cmethod);
10794
10795                         if (mono_security_core_clr_enabled ())
10796                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
10797
10798                         if (cfg->gshared && cmethod && cmethod->klass != method->klass && cmethod->klass->generic_class && mono_method_is_generic_sharable (cmethod, TRUE) && mono_class_needs_cctor_run (cmethod->klass, method)) {
10799                                 emit_class_init (cfg, cmethod->klass);
10800                                 CHECK_TYPELOAD (cmethod->klass);
10801                         }
10802
10803                         /*
10804                         if (cfg->gsharedvt) {
10805                                 if (mini_is_gsharedvt_variable_signature (sig))
10806                                         GSHAREDVT_FAILURE (*ip);
10807                         }
10808                         */
10809
10810                         n = fsig->param_count;
10811                         CHECK_STACK (n);
10812
10813                         /* 
10814                          * Generate smaller code for the common newobj <exception> instruction in
10815                          * argument checking code.
10816                          */
10817                         if (cfg->cbb->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
10818                                 is_exception_class (cmethod->klass) && n <= 2 &&
10819                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
10820                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
10821                                 MonoInst *iargs [3];
10822
10823                                 sp -= n;
10824
10825                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
10826                                 switch (n) {
10827                                 case 0:
10828                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
10829                                         break;
10830                                 case 1:
10831                                         iargs [1] = sp [0];
10832                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
10833                                         break;
10834                                 case 2:
10835                                         iargs [1] = sp [0];
10836                                         iargs [2] = sp [1];
10837                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
10838                                         break;
10839                                 default:
10840                                         g_assert_not_reached ();
10841                                 }
10842
10843                                 ip += 5;
10844                                 inline_costs += 5;
10845                                 break;
10846                         }
10847
10848                         /* move the args to allow room for 'this' in the first position */
10849                         while (n--) {
10850                                 --sp;
10851                                 sp [1] = sp [0];
10852                         }
10853
10854                         /* check_call_signature () requires sp[0] to be set */
10855                         this_ins.type = STACK_OBJ;
10856                         sp [0] = &this_ins;
10857                         if (check_call_signature (cfg, fsig, sp))
10858                                 UNVERIFIED;
10859
10860                         iargs [0] = NULL;
10861
10862                         if (mini_class_is_system_array (cmethod->klass)) {
10863                                 *sp = emit_get_rgctx_method (cfg, context_used,
10864                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
10865
10866                                 /* Avoid varargs in the common case */
10867                                 if (fsig->param_count == 1)
10868                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
10869                                 else if (fsig->param_count == 2)
10870                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
10871                                 else if (fsig->param_count == 3)
10872                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
10873                                 else if (fsig->param_count == 4)
10874                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
10875                                 else
10876                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
10877                         } else if (cmethod->string_ctor) {
10878                                 g_assert (!context_used);
10879                                 g_assert (!vtable_arg);
10880                                 /* we simply pass a null pointer */
10881                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
10882                                 /* now call the string ctor */
10883                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
10884                         } else {
10885                                 if (cmethod->klass->valuetype) {
10886                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
10887                                         emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
10888                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
10889
10890                                         alloc = NULL;
10891
10892                                         /* 
10893                                          * The code generated by mini_emit_virtual_call () expects
10894                                          * iargs [0] to be a boxed instance, but luckily the vcall
10895                                          * will be transformed into a normal call there.
10896                                          */
10897                                 } else if (context_used) {
10898                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
10899                                         *sp = alloc;
10900                                 } else {
10901                                         MonoVTable *vtable = NULL;
10902
10903                                         if (!cfg->compile_aot)
10904                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
10905                                         CHECK_TYPELOAD (cmethod->klass);
10906
10907                                         /*
10908                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
10909                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
10910                                          * As a workaround, we call class cctors before allocating objects.
10911                                          */
10912                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
10913                                                 emit_class_init (cfg, cmethod->klass);
10914                                                 if (cfg->verbose_level > 2)
10915                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
10916                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
10917                                         }
10918
10919                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
10920                                         *sp = alloc;
10921                                 }
10922                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
10923
10924                                 if (alloc)
10925                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
10926
10927                                 /* Now call the actual ctor */
10928                                 handle_ctor_call (cfg, cmethod, fsig, context_used, sp, ip, &inline_costs);
10929                                 CHECK_CFG_EXCEPTION;
10930                         }
10931
10932                         if (alloc == NULL) {
10933                                 /* Valuetype */
10934                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
10935                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
10936                                 *sp++= ins;
10937                         } else {
10938                                 *sp++ = alloc;
10939                         }
10940                         
10941                         ip += 5;
10942                         inline_costs += 5;
10943                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip - header->code)))
10944                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10945                         break;
10946                 }
10947                 case CEE_CASTCLASS:
10948                         CHECK_STACK (1);
10949                         --sp;
10950                         CHECK_OPSIZE (5);
10951                         token = read32 (ip + 1);
10952                         klass = mini_get_class (method, token, generic_context);
10953                         CHECK_TYPELOAD (klass);
10954                         if (sp [0]->type != STACK_OBJ)
10955                                 UNVERIFIED;
10956
10957                         ins = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
10958                         CHECK_CFG_EXCEPTION;
10959
10960                         *sp ++ = ins;
10961                         ip += 5;
10962                         break;
10963                 case CEE_ISINST: {
10964                         CHECK_STACK (1);
10965                         --sp;
10966                         CHECK_OPSIZE (5);
10967                         token = read32 (ip + 1);
10968                         klass = mini_get_class (method, token, generic_context);
10969                         CHECK_TYPELOAD (klass);
10970                         if (sp [0]->type != STACK_OBJ)
10971                                 UNVERIFIED;
10972  
10973                         context_used = mini_class_check_context_used (cfg, klass);
10974
10975                         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
10976                                 MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
10977                                 MonoInst *args [3];
10978                                 int idx;
10979
10980                                 /* obj */
10981                                 args [0] = *sp;
10982
10983                                 /* klass */
10984                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
10985
10986                                 /* inline cache*/
10987                                 idx = get_castclass_cache_idx (cfg);
10988                                 args [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
10989
10990                                 *sp++ = mono_emit_method_call (cfg, mono_isinst, args, NULL);
10991                                 ip += 5;
10992                                 inline_costs += 2;
10993                         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
10994                                 MonoMethod *mono_isinst;
10995                                 MonoInst *iargs [1];
10996                                 int costs;
10997
10998                                 mono_isinst = mono_marshal_get_isinst (klass); 
10999                                 iargs [0] = sp [0];
11000
11001                                 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), 
11002                                                                            iargs, ip, cfg->real_offset, TRUE);
11003                                 CHECK_CFG_EXCEPTION;
11004                                 g_assert (costs > 0);
11005                                 
11006                                 ip += 5;
11007                                 cfg->real_offset += 5;
11008
11009                                 *sp++= iargs [0];
11010
11011                                 inline_costs += costs;
11012                         }
11013                         else {
11014                                 ins = handle_isinst (cfg, klass, *sp, context_used);
11015                                 CHECK_CFG_EXCEPTION;
11016                                 *sp ++ = ins;
11017                                 ip += 5;
11018                         }
11019                         break;
11020                 }
11021                 case CEE_UNBOX_ANY: {
11022                         MonoInst *res, *addr;
11023
11024                         CHECK_STACK (1);
11025                         --sp;
11026                         CHECK_OPSIZE (5);
11027                         token = read32 (ip + 1);
11028                         klass = mini_get_class (method, token, generic_context);
11029                         CHECK_TYPELOAD (klass);
11030
11031                         mono_save_token_info (cfg, image, token, klass);
11032
11033                         context_used = mini_class_check_context_used (cfg, klass);
11034
11035                         if (mini_is_gsharedvt_klass (klass)) {
11036                                 res = handle_unbox_gsharedvt (cfg, klass, *sp);
11037                                 inline_costs += 2;
11038                         } else if (generic_class_is_reference_type (cfg, klass)) {
11039                                 res = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
11040                                 CHECK_CFG_EXCEPTION;
11041                         } else if (mono_class_is_nullable (klass)) {
11042                                 res = handle_unbox_nullable (cfg, *sp, klass, context_used);
11043                         } else {
11044                                 addr = handle_unbox (cfg, klass, sp, context_used);
11045                                 /* LDOBJ */
11046                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11047                                 res = ins;
11048                                 inline_costs += 2;
11049                         }
11050
11051                         *sp ++ = res;
11052                         ip += 5;
11053                         break;
11054                 }
11055                 case CEE_BOX: {
11056                         MonoInst *val;
11057                         MonoClass *enum_class;
11058                         MonoMethod *has_flag;
11059
11060                         CHECK_STACK (1);
11061                         --sp;
11062                         val = *sp;
11063                         CHECK_OPSIZE (5);
11064                         token = read32 (ip + 1);
11065                         klass = mini_get_class (method, token, generic_context);
11066                         CHECK_TYPELOAD (klass);
11067
11068                         mono_save_token_info (cfg, image, token, klass);
11069
11070                         context_used = mini_class_check_context_used (cfg, klass);
11071
11072                         if (generic_class_is_reference_type (cfg, klass)) {
11073                                 *sp++ = val;
11074                                 ip += 5;
11075                                 break;
11076                         }
11077
11078                         if (klass == mono_defaults.void_class)
11079                                 UNVERIFIED;
11080                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
11081                                 UNVERIFIED;
11082                         /* frequent check in generic code: box (struct), brtrue */
11083
11084                         /*
11085                          * Look for:
11086                          *
11087                          *   <push int/long ptr>
11088                          *   <push int/long>
11089                          *   box MyFlags
11090                          *   constrained. MyFlags
11091                          *   callvirt instace bool class [mscorlib] System.Enum::HasFlag (class [mscorlib] System.Enum)
11092                          *
11093                          * If we find this sequence and the operand types on box and constrained
11094                          * are equal, we can emit a specialized instruction sequence instead of
11095                          * the very slow HasFlag () call.
11096                          */
11097                         if ((cfg->opt & MONO_OPT_INTRINS) &&
11098                             /* Cheap checks first. */
11099                             ip + 5 + 6 + 5 < end &&
11100                             ip [5] == CEE_PREFIX1 &&
11101                             ip [6] == CEE_CONSTRAINED_ &&
11102                             ip [11] == CEE_CALLVIRT &&
11103                             ip_in_bb (cfg, cfg->cbb, ip + 5 + 6 + 5) &&
11104                             mono_class_is_enum (klass) &&
11105                             (enum_class = mini_get_class (method, read32 (ip + 7), generic_context)) &&
11106                             (has_flag = mini_get_method (cfg, method, read32 (ip + 12), NULL, generic_context)) &&
11107                             has_flag->klass == mono_defaults.enum_class &&
11108                             !strcmp (has_flag->name, "HasFlag") &&
11109                             has_flag->signature->hasthis &&
11110                             has_flag->signature->param_count == 1) {
11111                                 CHECK_TYPELOAD (enum_class);
11112
11113                                 if (enum_class == klass) {
11114                                         MonoInst *enum_this, *enum_flag;
11115
11116                                         ip += 5 + 6 + 5;
11117                                         --sp;
11118
11119                                         enum_this = sp [0];
11120                                         enum_flag = sp [1];
11121
11122                                         *sp++ = handle_enum_has_flag (cfg, klass, enum_this, enum_flag);
11123                                         break;
11124                                 }
11125                         }
11126
11127                         // FIXME: LLVM can't handle the inconsistent bb linking
11128                         if (!mono_class_is_nullable (klass) &&
11129                                 !mini_is_gsharedvt_klass (klass) &&
11130                                 ip + 5 < end && ip_in_bb (cfg, cfg->cbb, ip + 5) &&
11131                                 (ip [5] == CEE_BRTRUE || 
11132                                  ip [5] == CEE_BRTRUE_S ||
11133                                  ip [5] == CEE_BRFALSE ||
11134                                  ip [5] == CEE_BRFALSE_S)) {
11135                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
11136                                 int dreg;
11137                                 MonoBasicBlock *true_bb, *false_bb;
11138
11139                                 ip += 5;
11140
11141                                 if (cfg->verbose_level > 3) {
11142                                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
11143                                         printf ("<box+brtrue opt>\n");
11144                                 }
11145
11146                                 switch (*ip) {
11147                                 case CEE_BRTRUE_S:
11148                                 case CEE_BRFALSE_S:
11149                                         CHECK_OPSIZE (2);
11150                                         ip++;
11151                                         target = ip + 1 + (signed char)(*ip);
11152                                         ip++;
11153                                         break;
11154                                 case CEE_BRTRUE:
11155                                 case CEE_BRFALSE:
11156                                         CHECK_OPSIZE (5);
11157                                         ip++;
11158                                         target = ip + 4 + (gint)(read32 (ip));
11159                                         ip += 4;
11160                                         break;
11161                                 default:
11162                                         g_assert_not_reached ();
11163                                 }
11164
11165                                 /* 
11166                                  * We need to link both bblocks, since it is needed for handling stack
11167                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
11168                                  * Branching to only one of them would lead to inconsistencies, so
11169                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
11170                                  */
11171                                 GET_BBLOCK (cfg, true_bb, target);
11172                                 GET_BBLOCK (cfg, false_bb, ip);
11173
11174                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
11175                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
11176
11177                                 if (sp != stack_start) {
11178                                         handle_stack_args (cfg, stack_start, sp - stack_start);
11179                                         sp = stack_start;
11180                                         CHECK_UNVERIFIABLE (cfg);
11181                                 }
11182
11183                                 if (COMPILE_LLVM (cfg)) {
11184                                         dreg = alloc_ireg (cfg);
11185                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
11186                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
11187
11188                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
11189                                 } else {
11190                                         /* The JIT can't eliminate the iconst+compare */
11191                                         MONO_INST_NEW (cfg, ins, OP_BR);
11192                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
11193                                         MONO_ADD_INS (cfg->cbb, ins);
11194                                 }
11195
11196                                 start_new_bblock = 1;
11197                                 break;
11198                         }
11199
11200                         *sp++ = handle_box (cfg, val, klass, context_used);
11201
11202                         CHECK_CFG_EXCEPTION;
11203                         ip += 5;
11204                         inline_costs += 1;
11205                         break;
11206                 }
11207                 case CEE_UNBOX: {
11208                         CHECK_STACK (1);
11209                         --sp;
11210                         CHECK_OPSIZE (5);
11211                         token = read32 (ip + 1);
11212                         klass = mini_get_class (method, token, generic_context);
11213                         CHECK_TYPELOAD (klass);
11214
11215                         mono_save_token_info (cfg, image, token, klass);
11216
11217                         context_used = mini_class_check_context_used (cfg, klass);
11218
11219                         if (mono_class_is_nullable (klass)) {
11220                                 MonoInst *val;
11221
11222                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
11223                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
11224
11225                                 *sp++= ins;
11226                         } else {
11227                                 ins = handle_unbox (cfg, klass, sp, context_used);
11228                                 *sp++ = ins;
11229                         }
11230                         ip += 5;
11231                         inline_costs += 2;
11232                         break;
11233                 }
11234                 case CEE_LDFLD:
11235                 case CEE_LDFLDA:
11236                 case CEE_STFLD:
11237                 case CEE_LDSFLD:
11238                 case CEE_LDSFLDA:
11239                 case CEE_STSFLD: {
11240                         MonoClassField *field;
11241 #ifndef DISABLE_REMOTING
11242                         int costs;
11243 #endif
11244                         guint foffset;
11245                         gboolean is_instance;
11246                         int op;
11247                         gpointer addr = NULL;
11248                         gboolean is_special_static;
11249                         MonoType *ftype;
11250                         MonoInst *store_val = NULL;
11251                         MonoInst *thread_ins;
11252
11253                         op = *ip;
11254                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
11255                         if (is_instance) {
11256                                 if (op == CEE_STFLD) {
11257                                         CHECK_STACK (2);
11258                                         sp -= 2;
11259                                         store_val = sp [1];
11260                                 } else {
11261                                         CHECK_STACK (1);
11262                                         --sp;
11263                                 }
11264                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
11265                                         UNVERIFIED;
11266                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
11267                                         UNVERIFIED;
11268                         } else {
11269                                 if (op == CEE_STSFLD) {
11270                                         CHECK_STACK (1);
11271                                         sp--;
11272                                         store_val = sp [0];
11273                                 }
11274                         }
11275
11276                         CHECK_OPSIZE (5);
11277                         token = read32 (ip + 1);
11278                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
11279                                 field = (MonoClassField *)mono_method_get_wrapper_data (method, token);
11280                                 klass = field->parent;
11281                         }
11282                         else {
11283                                 field = mono_field_from_token_checked (image, token, &klass, generic_context, &cfg->error);
11284                                 CHECK_CFG_ERROR;
11285                         }
11286                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
11287                                 FIELD_ACCESS_FAILURE (method, field);
11288                         mono_class_init (klass);
11289
11290                         /* if the class is Critical then transparent code cannot access it's fields */
11291                         if (!is_instance && mono_security_core_clr_enabled ())
11292                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
11293
11294                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
11295                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
11296                         if (mono_security_core_clr_enabled ())
11297                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
11298                         */
11299
11300                         ftype = mono_field_get_type (field);
11301
11302                         /*
11303                          * LDFLD etc. is usable on static fields as well, so convert those cases to
11304                          * the static case.
11305                          */
11306                         if (is_instance && ftype->attrs & FIELD_ATTRIBUTE_STATIC) {
11307                                 switch (op) {
11308                                 case CEE_LDFLD:
11309                                         op = CEE_LDSFLD;
11310                                         break;
11311                                 case CEE_STFLD:
11312                                         op = CEE_STSFLD;
11313                                         break;
11314                                 case CEE_LDFLDA:
11315                                         op = CEE_LDSFLDA;
11316                                         break;
11317                                 default:
11318                                         g_assert_not_reached ();
11319                                 }
11320                                 is_instance = FALSE;
11321                         }
11322
11323                         context_used = mini_class_check_context_used (cfg, klass);
11324
11325                         /* INSTANCE CASE */
11326
11327                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
11328                         if (op == CEE_STFLD) {
11329                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
11330                                         UNVERIFIED;
11331 #ifndef DISABLE_REMOTING
11332                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
11333                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
11334                                         MonoInst *iargs [5];
11335
11336                                         GSHAREDVT_FAILURE (op);
11337
11338                                         iargs [0] = sp [0];
11339                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11340                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
11341                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
11342                                                     field->offset);
11343                                         iargs [4] = sp [1];
11344
11345                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
11346                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
11347                                                                                            iargs, ip, cfg->real_offset, TRUE);
11348                                                 CHECK_CFG_EXCEPTION;
11349                                                 g_assert (costs > 0);
11350                                                       
11351                                                 cfg->real_offset += 5;
11352
11353                                                 inline_costs += costs;
11354                                         } else {
11355                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
11356                                         }
11357                                 } else
11358 #endif
11359                                 {
11360                                         MonoInst *store;
11361
11362                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
11363
11364                                         if (mini_is_gsharedvt_klass (klass)) {
11365                                                 MonoInst *offset_ins;
11366
11367                                                 context_used = mini_class_check_context_used (cfg, klass);
11368
11369                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11370                                                 /* The value is offset by 1 */
11371                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11372                                                 dreg = alloc_ireg_mp (cfg);
11373                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11374                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
11375                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
11376                                         } else {
11377                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
11378                                         }
11379                                         if (sp [0]->opcode != OP_LDADDR)
11380                                                 store->flags |= MONO_INST_FAULT;
11381
11382                                 if (cfg->gen_write_barriers && mini_type_to_stind (cfg, field->type) == CEE_STIND_REF && !(sp [1]->opcode == OP_PCONST && sp [1]->inst_c0 == 0)) {
11383                                         /* insert call to write barrier */
11384                                         MonoInst *ptr;
11385                                         int dreg;
11386
11387                                         dreg = alloc_ireg_mp (cfg);
11388                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
11389                                         emit_write_barrier (cfg, ptr, sp [1]);
11390                                 }
11391
11392                                         store->flags |= ins_flag;
11393                                 }
11394                                 ins_flag = 0;
11395                                 ip += 5;
11396                                 break;
11397                         }
11398
11399 #ifndef DISABLE_REMOTING
11400                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
11401                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
11402                                 MonoInst *iargs [4];
11403
11404                                 GSHAREDVT_FAILURE (op);
11405
11406                                 iargs [0] = sp [0];
11407                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11408                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
11409                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
11410                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
11411                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
11412                                                                                    iargs, ip, cfg->real_offset, TRUE);
11413                                         CHECK_CFG_EXCEPTION;
11414                                         g_assert (costs > 0);
11415                                                       
11416                                         cfg->real_offset += 5;
11417
11418                                         *sp++ = iargs [0];
11419
11420                                         inline_costs += costs;
11421                                 } else {
11422                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
11423                                         *sp++ = ins;
11424                                 }
11425                         } else 
11426 #endif
11427                         if (is_instance) {
11428                                 if (sp [0]->type == STACK_VTYPE) {
11429                                         MonoInst *var;
11430
11431                                         /* Have to compute the address of the variable */
11432
11433                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
11434                                         if (!var)
11435                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
11436                                         else
11437                                                 g_assert (var->klass == klass);
11438                                         
11439                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
11440                                         sp [0] = ins;
11441                                 }
11442
11443                                 if (op == CEE_LDFLDA) {
11444                                         if (sp [0]->type == STACK_OBJ) {
11445                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
11446                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
11447                                         }
11448
11449                                         dreg = alloc_ireg_mp (cfg);
11450
11451                                         if (mini_is_gsharedvt_klass (klass)) {
11452                                                 MonoInst *offset_ins;
11453
11454                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11455                                                 /* The value is offset by 1 */
11456                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11457                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11458                                         } else {
11459                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
11460                                         }
11461                                         ins->klass = mono_class_from_mono_type (field->type);
11462                                         ins->type = STACK_MP;
11463                                         *sp++ = ins;
11464                                 } else {
11465                                         MonoInst *load;
11466
11467                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
11468
11469                                         if (mini_is_gsharedvt_klass (klass)) {
11470                                                 MonoInst *offset_ins;
11471
11472                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11473                                                 /* The value is offset by 1 */
11474                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11475                                                 dreg = alloc_ireg_mp (cfg);
11476                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11477                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
11478                                         } else {
11479                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
11480                                         }
11481                                         load->flags |= ins_flag;
11482                                         if (sp [0]->opcode != OP_LDADDR)
11483                                                 load->flags |= MONO_INST_FAULT;
11484                                         *sp++ = load;
11485                                 }
11486                         }
11487
11488                         if (is_instance) {
11489                                 ins_flag = 0;
11490                                 ip += 5;
11491                                 break;
11492                         }
11493
11494                         /* STATIC CASE */
11495                         context_used = mini_class_check_context_used (cfg, klass);
11496
11497                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL) {
11498                                 mono_error_set_field_load (&cfg->error, field->parent, field->name, "Using static instructions with literal field");
11499                                 CHECK_CFG_ERROR;
11500                         }
11501
11502                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
11503                          * to be called here.
11504                          */
11505                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
11506                                 mono_class_vtable (cfg->domain, klass);
11507                                 CHECK_TYPELOAD (klass);
11508                         }
11509                         mono_domain_lock (cfg->domain);
11510                         if (cfg->domain->special_static_fields)
11511                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
11512                         mono_domain_unlock (cfg->domain);
11513
11514                         is_special_static = mono_class_field_is_special_static (field);
11515
11516                         if (is_special_static && ((gsize)addr & 0x80000000) == 0)
11517                                 thread_ins = mono_get_thread_intrinsic (cfg);
11518                         else
11519                                 thread_ins = NULL;
11520
11521                         /* Generate IR to compute the field address */
11522                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
11523                                 /*
11524                                  * Fast access to TLS data
11525                                  * Inline version of get_thread_static_data () in
11526                                  * threads.c.
11527                                  */
11528                                 guint32 offset;
11529                                 int idx, static_data_reg, array_reg, dreg;
11530
11531                                 GSHAREDVT_FAILURE (op);
11532
11533                                 MONO_ADD_INS (cfg->cbb, thread_ins);
11534                                 static_data_reg = alloc_ireg (cfg);
11535                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
11536
11537                                 if (cfg->compile_aot) {
11538                                         int offset_reg, offset2_reg, idx_reg;
11539
11540                                         /* For TLS variables, this will return the TLS offset */
11541                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
11542                                         offset_reg = ins->dreg;
11543                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
11544                                         idx_reg = alloc_ireg (cfg);
11545                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, idx_reg, offset_reg, 0x3f);
11546                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
11547                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
11548                                         array_reg = alloc_ireg (cfg);
11549                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
11550                                         offset2_reg = alloc_ireg (cfg);
11551                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, offset2_reg, offset_reg, 6);
11552                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset2_reg, 0x1ffffff);
11553                                         dreg = alloc_ireg (cfg);
11554                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
11555                                 } else {
11556                                         offset = (gsize)addr & 0x7fffffff;
11557                                         idx = offset & 0x3f;
11558
11559                                         array_reg = alloc_ireg (cfg);
11560                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
11561                                         dreg = alloc_ireg (cfg);
11562                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, ((offset >> 6) & 0x1ffffff));
11563                                 }
11564                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
11565                                         (cfg->compile_aot && is_special_static) ||
11566                                         (context_used && is_special_static)) {
11567                                 MonoInst *iargs [2];
11568
11569                                 g_assert (field->parent);
11570                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11571                                 if (context_used) {
11572                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
11573                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
11574                                 } else {
11575                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11576                                 }
11577                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11578                         } else if (context_used) {
11579                                 MonoInst *static_data;
11580
11581                                 /*
11582                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
11583                                         method->klass->name_space, method->klass->name, method->name,
11584                                         depth, field->offset);
11585                                 */
11586
11587                                 if (mono_class_needs_cctor_run (klass, method))
11588                                         emit_class_init (cfg, klass);
11589
11590                                 /*
11591                                  * The pointer we're computing here is
11592                                  *
11593                                  *   super_info.static_data + field->offset
11594                                  */
11595                                 static_data = emit_get_rgctx_klass (cfg, context_used,
11596                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
11597
11598                                 if (mini_is_gsharedvt_klass (klass)) {
11599                                         MonoInst *offset_ins;
11600
11601                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11602                                         /* The value is offset by 1 */
11603                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11604                                         dreg = alloc_ireg_mp (cfg);
11605                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
11606                                 } else if (field->offset == 0) {
11607                                         ins = static_data;
11608                                 } else {
11609                                         int addr_reg = mono_alloc_preg (cfg);
11610                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
11611                                 }
11612                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
11613                                 MonoInst *iargs [2];
11614
11615                                 g_assert (field->parent);
11616                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11617                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11618                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11619                         } else {
11620                                 MonoVTable *vtable = NULL;
11621
11622                                 if (!cfg->compile_aot)
11623                                         vtable = mono_class_vtable (cfg->domain, klass);
11624                                 CHECK_TYPELOAD (klass);
11625
11626                                 if (!addr) {
11627                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
11628                                                 if (!(g_slist_find (class_inits, klass))) {
11629                                                         emit_class_init (cfg, klass);
11630                                                         if (cfg->verbose_level > 2)
11631                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
11632                                                         class_inits = g_slist_prepend (class_inits, klass);
11633                                                 }
11634                                         } else {
11635                                                 if (cfg->run_cctors) {
11636                                                         /* This makes so that inline cannot trigger */
11637                                                         /* .cctors: too many apps depend on them */
11638                                                         /* running with a specific order... */
11639                                                         g_assert (vtable);
11640                                                         if (! vtable->initialized)
11641                                                                 INLINE_FAILURE ("class init");
11642                                                         if (!mono_runtime_class_init_full (vtable, &cfg->error)) {
11643                                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
11644                                                                 g_assert_not_reached ();
11645                                                                 goto exception_exit;
11646                                                         }
11647                                                 }
11648                                         }
11649                                         if (cfg->compile_aot)
11650                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
11651                                         else {
11652                                                 g_assert (vtable);
11653                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11654                                                 g_assert (addr);
11655                                                 EMIT_NEW_PCONST (cfg, ins, addr);
11656                                         }
11657                                 } else {
11658                                         MonoInst *iargs [1];
11659                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
11660                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
11661                                 }
11662                         }
11663
11664                         /* Generate IR to do the actual load/store operation */
11665
11666                         if ((op == CEE_STFLD || op == CEE_STSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11667                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11668                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11669                         }
11670
11671                         if (op == CEE_LDSFLDA) {
11672                                 ins->klass = mono_class_from_mono_type (ftype);
11673                                 ins->type = STACK_PTR;
11674                                 *sp++ = ins;
11675                         } else if (op == CEE_STSFLD) {
11676                                 MonoInst *store;
11677
11678                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
11679                                 store->flags |= ins_flag;
11680                         } else {
11681                                 gboolean is_const = FALSE;
11682                                 MonoVTable *vtable = NULL;
11683                                 gpointer addr = NULL;
11684
11685                                 if (!context_used) {
11686                                         vtable = mono_class_vtable (cfg->domain, klass);
11687                                         CHECK_TYPELOAD (klass);
11688                                 }
11689                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
11690                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
11691                                         int ro_type = ftype->type;
11692                                         if (!addr)
11693                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11694                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
11695                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
11696                                         }
11697
11698                                         GSHAREDVT_FAILURE (op);
11699
11700                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
11701                                         is_const = TRUE;
11702                                         switch (ro_type) {
11703                                         case MONO_TYPE_BOOLEAN:
11704                                         case MONO_TYPE_U1:
11705                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
11706                                                 sp++;
11707                                                 break;
11708                                         case MONO_TYPE_I1:
11709                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
11710                                                 sp++;
11711                                                 break;                                          
11712                                         case MONO_TYPE_CHAR:
11713                                         case MONO_TYPE_U2:
11714                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
11715                                                 sp++;
11716                                                 break;
11717                                         case MONO_TYPE_I2:
11718                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
11719                                                 sp++;
11720                                                 break;
11721                                                 break;
11722                                         case MONO_TYPE_I4:
11723                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
11724                                                 sp++;
11725                                                 break;                                          
11726                                         case MONO_TYPE_U4:
11727                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
11728                                                 sp++;
11729                                                 break;
11730                                         case MONO_TYPE_I:
11731                                         case MONO_TYPE_U:
11732                                         case MONO_TYPE_PTR:
11733                                         case MONO_TYPE_FNPTR:
11734                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11735                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
11736                                                 sp++;
11737                                                 break;
11738                                         case MONO_TYPE_STRING:
11739                                         case MONO_TYPE_OBJECT:
11740                                         case MONO_TYPE_CLASS:
11741                                         case MONO_TYPE_SZARRAY:
11742                                         case MONO_TYPE_ARRAY:
11743                                                 if (!mono_gc_is_moving ()) {
11744                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11745                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
11746                                                         sp++;
11747                                                 } else {
11748                                                         is_const = FALSE;
11749                                                 }
11750                                                 break;
11751                                         case MONO_TYPE_I8:
11752                                         case MONO_TYPE_U8:
11753                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
11754                                                 sp++;
11755                                                 break;
11756                                         case MONO_TYPE_R4:
11757                                         case MONO_TYPE_R8:
11758                                         case MONO_TYPE_VALUETYPE:
11759                                         default:
11760                                                 is_const = FALSE;
11761                                                 break;
11762                                         }
11763                                 }
11764
11765                                 if (!is_const) {
11766                                         MonoInst *load;
11767
11768                                         CHECK_STACK_OVF (1);
11769
11770                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
11771                                         load->flags |= ins_flag;
11772                                         ins_flag = 0;
11773                                         *sp++ = load;
11774                                 }
11775                         }
11776
11777                         if ((op == CEE_LDFLD || op == CEE_LDSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11778                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
11779                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
11780                         }
11781
11782                         ins_flag = 0;
11783                         ip += 5;
11784                         break;
11785                 }
11786                 case CEE_STOBJ:
11787                         CHECK_STACK (2);
11788                         sp -= 2;
11789                         CHECK_OPSIZE (5);
11790                         token = read32 (ip + 1);
11791                         klass = mini_get_class (method, token, generic_context);
11792                         CHECK_TYPELOAD (klass);
11793                         if (ins_flag & MONO_INST_VOLATILE) {
11794                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11795                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11796                         }
11797                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
11798                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
11799                         ins->flags |= ins_flag;
11800                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
11801                                         generic_class_is_reference_type (cfg, klass)) {
11802                                 /* insert call to write barrier */
11803                                 emit_write_barrier (cfg, sp [0], sp [1]);
11804                         }
11805                         ins_flag = 0;
11806                         ip += 5;
11807                         inline_costs += 1;
11808                         break;
11809
11810                         /*
11811                          * Array opcodes
11812                          */
11813                 case CEE_NEWARR: {
11814                         MonoInst *len_ins;
11815                         const char *data_ptr;
11816                         int data_size = 0;
11817                         guint32 field_token;
11818
11819                         CHECK_STACK (1);
11820                         --sp;
11821
11822                         CHECK_OPSIZE (5);
11823                         token = read32 (ip + 1);
11824
11825                         klass = mini_get_class (method, token, generic_context);
11826                         CHECK_TYPELOAD (klass);
11827
11828                         context_used = mini_class_check_context_used (cfg, klass);
11829
11830                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
11831                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
11832                                 ins->sreg1 = sp [0]->dreg;
11833                                 ins->type = STACK_I4;
11834                                 ins->dreg = alloc_ireg (cfg);
11835                                 MONO_ADD_INS (cfg->cbb, ins);
11836                                 *sp = mono_decompose_opcode (cfg, ins);
11837                         }
11838
11839                         if (context_used) {
11840                                 MonoInst *args [3];
11841                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11842                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
11843
11844                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
11845
11846                                 /* vtable */
11847                                 args [0] = emit_get_rgctx_klass (cfg, context_used,
11848                                         array_class, MONO_RGCTX_INFO_VTABLE);
11849                                 /* array len */
11850                                 args [1] = sp [0];
11851
11852                                 if (managed_alloc)
11853                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
11854                                 else
11855                                         ins = mono_emit_jit_icall (cfg, ves_icall_array_new_specific, args);
11856                         } else {
11857                                 if (cfg->opt & MONO_OPT_SHARED) {
11858                                         /* Decompose now to avoid problems with references to the domainvar */
11859                                         MonoInst *iargs [3];
11860
11861                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11862                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11863                                         iargs [2] = sp [0];
11864
11865                                         ins = mono_emit_jit_icall (cfg, mono_array_new, iargs);
11866                                 } else {
11867                                         /* Decompose later since it is needed by abcrem */
11868                                         MonoClass *array_type = mono_array_class_get (klass, 1);
11869                                         mono_class_vtable (cfg->domain, array_type);
11870                                         CHECK_TYPELOAD (array_type);
11871
11872                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
11873                                         ins->dreg = alloc_ireg_ref (cfg);
11874                                         ins->sreg1 = sp [0]->dreg;
11875                                         ins->inst_newa_class = klass;
11876                                         ins->type = STACK_OBJ;
11877                                         ins->klass = array_type;
11878                                         MONO_ADD_INS (cfg->cbb, ins);
11879                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11880                                         cfg->cbb->has_array_access = TRUE;
11881
11882                                         /* Needed so mono_emit_load_get_addr () gets called */
11883                                         mono_get_got_var (cfg);
11884                                 }
11885                         }
11886
11887                         len_ins = sp [0];
11888                         ip += 5;
11889                         *sp++ = ins;
11890                         inline_costs += 1;
11891
11892                         /* 
11893                          * we inline/optimize the initialization sequence if possible.
11894                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
11895                          * for small sizes open code the memcpy
11896                          * ensure the rva field is big enough
11897                          */
11898                         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))) {
11899                                 MonoMethod *memcpy_method = get_memcpy_method ();
11900                                 MonoInst *iargs [3];
11901                                 int add_reg = alloc_ireg_mp (cfg);
11902
11903                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, MONO_STRUCT_OFFSET (MonoArray, vector));
11904                                 if (cfg->compile_aot) {
11905                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
11906                                 } else {
11907                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
11908                                 }
11909                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
11910                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
11911                                 ip += 11;
11912                         }
11913
11914                         break;
11915                 }
11916                 case CEE_LDLEN:
11917                         CHECK_STACK (1);
11918                         --sp;
11919                         if (sp [0]->type != STACK_OBJ)
11920                                 UNVERIFIED;
11921
11922                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
11923                         ins->dreg = alloc_preg (cfg);
11924                         ins->sreg1 = sp [0]->dreg;
11925                         ins->type = STACK_I4;
11926                         /* This flag will be inherited by the decomposition */
11927                         ins->flags |= MONO_INST_FAULT;
11928                         MONO_ADD_INS (cfg->cbb, ins);
11929                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11930                         cfg->cbb->has_array_access = TRUE;
11931                         ip ++;
11932                         *sp++ = ins;
11933                         break;
11934                 case CEE_LDELEMA:
11935                         CHECK_STACK (2);
11936                         sp -= 2;
11937                         CHECK_OPSIZE (5);
11938                         if (sp [0]->type != STACK_OBJ)
11939                                 UNVERIFIED;
11940
11941                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11942
11943                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11944                         CHECK_TYPELOAD (klass);
11945                         /* we need to make sure that this array is exactly the type it needs
11946                          * to be for correctness. the wrappers are lax with their usage
11947                          * so we need to ignore them here
11948                          */
11949                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
11950                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11951                                 mini_emit_check_array_type (cfg, sp [0], array_class);
11952                                 CHECK_TYPELOAD (array_class);
11953                         }
11954
11955                         readonly = FALSE;
11956                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11957                         *sp++ = ins;
11958                         ip += 5;
11959                         break;
11960                 case CEE_LDELEM:
11961                 case CEE_LDELEM_I1:
11962                 case CEE_LDELEM_U1:
11963                 case CEE_LDELEM_I2:
11964                 case CEE_LDELEM_U2:
11965                 case CEE_LDELEM_I4:
11966                 case CEE_LDELEM_U4:
11967                 case CEE_LDELEM_I8:
11968                 case CEE_LDELEM_I:
11969                 case CEE_LDELEM_R4:
11970                 case CEE_LDELEM_R8:
11971                 case CEE_LDELEM_REF: {
11972                         MonoInst *addr;
11973
11974                         CHECK_STACK (2);
11975                         sp -= 2;
11976
11977                         if (*ip == CEE_LDELEM) {
11978                                 CHECK_OPSIZE (5);
11979                                 token = read32 (ip + 1);
11980                                 klass = mini_get_class (method, token, generic_context);
11981                                 CHECK_TYPELOAD (klass);
11982                                 mono_class_init (klass);
11983                         }
11984                         else
11985                                 klass = array_access_to_klass (*ip);
11986
11987                         if (sp [0]->type != STACK_OBJ)
11988                                 UNVERIFIED;
11989
11990                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11991
11992                         if (mini_is_gsharedvt_variable_klass (klass)) {
11993                                 // FIXME-VT: OP_ICONST optimization
11994                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11995                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11996                                 ins->opcode = OP_LOADV_MEMBASE;
11997                         } else if (sp [1]->opcode == OP_ICONST) {
11998                                 int array_reg = sp [0]->dreg;
11999                                 int index_reg = sp [1]->dreg;
12000                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
12001
12002                                 if (SIZEOF_REGISTER == 8 && COMPILE_LLVM (cfg))
12003                                         MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, index_reg);
12004
12005                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
12006                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
12007                         } else {
12008                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
12009                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
12010                         }
12011                         *sp++ = ins;
12012                         if (*ip == CEE_LDELEM)
12013                                 ip += 5;
12014                         else
12015                                 ++ip;
12016                         break;
12017                 }
12018                 case CEE_STELEM_I:
12019                 case CEE_STELEM_I1:
12020                 case CEE_STELEM_I2:
12021                 case CEE_STELEM_I4:
12022                 case CEE_STELEM_I8:
12023                 case CEE_STELEM_R4:
12024                 case CEE_STELEM_R8:
12025                 case CEE_STELEM_REF:
12026                 case CEE_STELEM: {
12027                         CHECK_STACK (3);
12028                         sp -= 3;
12029
12030                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
12031
12032                         if (*ip == CEE_STELEM) {
12033                                 CHECK_OPSIZE (5);
12034                                 token = read32 (ip + 1);
12035                                 klass = mini_get_class (method, token, generic_context);
12036                                 CHECK_TYPELOAD (klass);
12037                                 mono_class_init (klass);
12038                         }
12039                         else
12040                                 klass = array_access_to_klass (*ip);
12041
12042                         if (sp [0]->type != STACK_OBJ)
12043                                 UNVERIFIED;
12044
12045                         emit_array_store (cfg, klass, sp, TRUE);
12046
12047                         if (*ip == CEE_STELEM)
12048                                 ip += 5;
12049                         else
12050                                 ++ip;
12051                         inline_costs += 1;
12052                         break;
12053                 }
12054                 case CEE_CKFINITE: {
12055                         CHECK_STACK (1);
12056                         --sp;
12057
12058                         if (cfg->llvm_only) {
12059                                 MonoInst *iargs [1];
12060
12061                                 iargs [0] = sp [0];
12062                                 *sp++ = mono_emit_jit_icall (cfg, mono_ckfinite, iargs);
12063                         } else  {
12064                                 MONO_INST_NEW (cfg, ins, OP_CKFINITE);
12065                                 ins->sreg1 = sp [0]->dreg;
12066                                 ins->dreg = alloc_freg (cfg);
12067                                 ins->type = STACK_R8;
12068                                 MONO_ADD_INS (cfg->cbb, ins);
12069
12070                                 *sp++ = mono_decompose_opcode (cfg, ins);
12071                         }
12072
12073                         ++ip;
12074                         break;
12075                 }
12076                 case CEE_REFANYVAL: {
12077                         MonoInst *src_var, *src;
12078
12079                         int klass_reg = alloc_preg (cfg);
12080                         int dreg = alloc_preg (cfg);
12081
12082                         GSHAREDVT_FAILURE (*ip);
12083
12084                         CHECK_STACK (1);
12085                         MONO_INST_NEW (cfg, ins, *ip);
12086                         --sp;
12087                         CHECK_OPSIZE (5);
12088                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
12089                         CHECK_TYPELOAD (klass);
12090
12091                         context_used = mini_class_check_context_used (cfg, klass);
12092
12093                         // FIXME:
12094                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12095                         if (!src_var)
12096                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
12097                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
12098                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass));
12099
12100                         if (context_used) {
12101                                 MonoInst *klass_ins;
12102
12103                                 klass_ins = emit_get_rgctx_klass (cfg, context_used,
12104                                                 klass, MONO_RGCTX_INFO_KLASS);
12105
12106                                 // FIXME:
12107                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
12108                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
12109                         } else {
12110                                 mini_emit_class_check (cfg, klass_reg, klass);
12111                         }
12112                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value));
12113                         ins->type = STACK_MP;
12114                         ins->klass = klass;
12115                         *sp++ = ins;
12116                         ip += 5;
12117                         break;
12118                 }
12119                 case CEE_MKREFANY: {
12120                         MonoInst *loc, *addr;
12121
12122                         GSHAREDVT_FAILURE (*ip);
12123
12124                         CHECK_STACK (1);
12125                         MONO_INST_NEW (cfg, ins, *ip);
12126                         --sp;
12127                         CHECK_OPSIZE (5);
12128                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
12129                         CHECK_TYPELOAD (klass);
12130
12131                         context_used = mini_class_check_context_used (cfg, klass);
12132
12133                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
12134                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
12135
12136                         if (context_used) {
12137                                 MonoInst *const_ins;
12138                                 int type_reg = alloc_preg (cfg);
12139
12140                                 const_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
12141                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
12142                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
12143                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
12144                         } else if (cfg->compile_aot) {
12145                                 int const_reg = alloc_preg (cfg);
12146                                 int type_reg = alloc_preg (cfg);
12147
12148                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
12149                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
12150                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
12151                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
12152                         } else {
12153                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), &klass->byval_arg);
12154                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), klass);
12155                         }
12156                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
12157
12158                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
12159                         ins->type = STACK_VTYPE;
12160                         ins->klass = mono_defaults.typed_reference_class;
12161                         *sp++ = ins;
12162                         ip += 5;
12163                         break;
12164                 }
12165                 case CEE_LDTOKEN: {
12166                         gpointer handle;
12167                         MonoClass *handle_class;
12168
12169                         CHECK_STACK_OVF (1);
12170
12171                         CHECK_OPSIZE (5);
12172                         n = read32 (ip + 1);
12173
12174                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
12175                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
12176                                 handle = mono_method_get_wrapper_data (method, n);
12177                                 handle_class = (MonoClass *)mono_method_get_wrapper_data (method, n + 1);
12178                                 if (handle_class == mono_defaults.typehandle_class)
12179                                         handle = &((MonoClass*)handle)->byval_arg;
12180                         }
12181                         else {
12182                                 handle = mono_ldtoken_checked (image, n, &handle_class, generic_context, &cfg->error);
12183                                 CHECK_CFG_ERROR;
12184                         }
12185                         if (!handle)
12186                                 LOAD_ERROR;
12187                         mono_class_init (handle_class);
12188                         if (cfg->gshared) {
12189                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
12190                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
12191                                         /* This case handles ldtoken
12192                                            of an open type, like for
12193                                            typeof(Gen<>). */
12194                                         context_used = 0;
12195                                 } else if (handle_class == mono_defaults.typehandle_class) {
12196                                         context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type ((MonoType *)handle));
12197                                 } else if (handle_class == mono_defaults.fieldhandle_class)
12198                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
12199                                 else if (handle_class == mono_defaults.methodhandle_class)
12200                                         context_used = mini_method_check_context_used (cfg, (MonoMethod *)handle);
12201                                 else
12202                                         g_assert_not_reached ();
12203                         }
12204
12205                         if ((cfg->opt & MONO_OPT_SHARED) &&
12206                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
12207                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
12208                                 MonoInst *addr, *vtvar, *iargs [3];
12209                                 int method_context_used;
12210
12211                                 method_context_used = mini_method_check_context_used (cfg, method);
12212
12213                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
12214
12215                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
12216                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
12217                                 if (method_context_used) {
12218                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
12219                                                 method, MONO_RGCTX_INFO_METHOD);
12220                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
12221                                 } else {
12222                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
12223                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
12224                                 }
12225                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12226
12227                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
12228
12229                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12230                         } else {
12231                                 if ((ip + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 5) && 
12232                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
12233                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
12234                                         (cmethod->klass == mono_defaults.systemtype_class) &&
12235                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
12236                                         MonoClass *tclass = mono_class_from_mono_type ((MonoType *)handle);
12237
12238                                         mono_class_init (tclass);
12239                                         if (context_used) {
12240                                                 ins = emit_get_rgctx_klass (cfg, context_used,
12241                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
12242                                         } else if (cfg->compile_aot) {
12243                                                 if (method->wrapper_type) {
12244                                                         mono_error_init (&error); //got to do it since there are multiple conditionals below
12245                                                         if (mono_class_get_checked (tclass->image, tclass->type_token, &error) == tclass && !generic_context) {
12246                                                                 /* Special case for static synchronized wrappers */
12247                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
12248                                                         } else {
12249                                                                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
12250                                                                 /* FIXME: n is not a normal token */
12251                                                                 DISABLE_AOT (cfg);
12252                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12253                                                         }
12254                                                 } else {
12255                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
12256                                                 }
12257                                         } else {
12258                                                 MonoReflectionType *rt = mono_type_get_object_checked (cfg->domain, (MonoType *)handle, &cfg->error);
12259                                                 CHECK_CFG_ERROR;
12260                                                 EMIT_NEW_PCONST (cfg, ins, rt);
12261                                         }
12262                                         ins->type = STACK_OBJ;
12263                                         ins->klass = cmethod->klass;
12264                                         ip += 5;
12265                                 } else {
12266                                         MonoInst *addr, *vtvar;
12267
12268                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
12269
12270                                         if (context_used) {
12271                                                 if (handle_class == mono_defaults.typehandle_class) {
12272                                                         ins = emit_get_rgctx_klass (cfg, context_used,
12273                                                                         mono_class_from_mono_type ((MonoType *)handle),
12274                                                                         MONO_RGCTX_INFO_TYPE);
12275                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
12276                                                         ins = emit_get_rgctx_method (cfg, context_used,
12277                                                                         (MonoMethod *)handle, MONO_RGCTX_INFO_METHOD);
12278                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
12279                                                         ins = emit_get_rgctx_field (cfg, context_used,
12280                                                                         (MonoClassField *)handle, MONO_RGCTX_INFO_CLASS_FIELD);
12281                                                 } else {
12282                                                         g_assert_not_reached ();
12283                                                 }
12284                                         } else if (cfg->compile_aot) {
12285                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
12286                                         } else {
12287                                                 EMIT_NEW_PCONST (cfg, ins, handle);
12288                                         }
12289                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12290                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
12291                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12292                                 }
12293                         }
12294
12295                         *sp++ = ins;
12296                         ip += 5;
12297                         break;
12298                 }
12299                 case CEE_THROW:
12300                         CHECK_STACK (1);
12301                         MONO_INST_NEW (cfg, ins, OP_THROW);
12302                         --sp;
12303                         ins->sreg1 = sp [0]->dreg;
12304                         ip++;
12305                         cfg->cbb->out_of_line = TRUE;
12306                         MONO_ADD_INS (cfg->cbb, ins);
12307                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
12308                         MONO_ADD_INS (cfg->cbb, ins);
12309                         sp = stack_start;
12310                         
12311                         link_bblock (cfg, cfg->cbb, end_bblock);
12312                         start_new_bblock = 1;
12313                         /* This can complicate code generation for llvm since the return value might not be defined */
12314                         if (COMPILE_LLVM (cfg))
12315                                 INLINE_FAILURE ("throw");
12316                         break;
12317                 case CEE_ENDFINALLY:
12318                         /* mono_save_seq_point_info () depends on this */
12319                         if (sp != stack_start)
12320                                 emit_seq_point (cfg, method, ip, FALSE, FALSE);
12321                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
12322                         MONO_ADD_INS (cfg->cbb, ins);
12323                         ip++;
12324                         start_new_bblock = 1;
12325
12326                         /*
12327                          * Control will leave the method so empty the stack, otherwise
12328                          * the next basic block will start with a nonempty stack.
12329                          */
12330                         while (sp != stack_start) {
12331                                 sp--;
12332                         }
12333                         break;
12334                 case CEE_LEAVE:
12335                 case CEE_LEAVE_S: {
12336                         GList *handlers;
12337
12338                         if (*ip == CEE_LEAVE) {
12339                                 CHECK_OPSIZE (5);
12340                                 target = ip + 5 + (gint32)read32(ip + 1);
12341                         } else {
12342                                 CHECK_OPSIZE (2);
12343                                 target = ip + 2 + (signed char)(ip [1]);
12344                         }
12345
12346                         /* empty the stack */
12347                         while (sp != stack_start) {
12348                                 sp--;
12349                         }
12350
12351                         /* 
12352                          * If this leave statement is in a catch block, check for a
12353                          * pending exception, and rethrow it if necessary.
12354                          * We avoid doing this in runtime invoke wrappers, since those are called
12355                          * by native code which excepts the wrapper to catch all exceptions.
12356                          */
12357                         for (i = 0; i < header->num_clauses; ++i) {
12358                                 MonoExceptionClause *clause = &header->clauses [i];
12359
12360                                 /* 
12361                                  * Use <= in the final comparison to handle clauses with multiple
12362                                  * leave statements, like in bug #78024.
12363                                  * The ordering of the exception clauses guarantees that we find the
12364                                  * innermost clause.
12365                                  */
12366                                 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) {
12367                                         MonoInst *exc_ins;
12368                                         MonoBasicBlock *dont_throw;
12369
12370                                         /*
12371                                           MonoInst *load;
12372
12373                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
12374                                         */
12375
12376                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
12377
12378                                         NEW_BBLOCK (cfg, dont_throw);
12379
12380                                         /*
12381                                          * Currently, we always rethrow the abort exception, despite the 
12382                                          * fact that this is not correct. See thread6.cs for an example. 
12383                                          * But propagating the abort exception is more important than 
12384                                          * getting the sematics right.
12385                                          */
12386                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
12387                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
12388                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
12389
12390                                         MONO_START_BB (cfg, dont_throw);
12391                                 }
12392                         }
12393
12394 #ifdef ENABLE_LLVM
12395                         cfg->cbb->try_end = (intptr_t)(ip - header->code);
12396 #endif
12397
12398                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
12399                                 GList *tmp;
12400                                 MonoExceptionClause *clause;
12401
12402                                 for (tmp = handlers; tmp; tmp = tmp->next) {
12403                                         clause = (MonoExceptionClause *)tmp->data;
12404                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
12405                                         g_assert (tblock);
12406                                         link_bblock (cfg, cfg->cbb, tblock);
12407                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
12408                                         ins->inst_target_bb = tblock;
12409                                         ins->inst_eh_block = clause;
12410                                         MONO_ADD_INS (cfg->cbb, ins);
12411                                         cfg->cbb->has_call_handler = 1;
12412                                         if (COMPILE_LLVM (cfg)) {
12413                                                 MonoBasicBlock *target_bb;
12414
12415                                                 /* 
12416                                                  * Link the finally bblock with the target, since it will
12417                                                  * conceptually branch there.
12418                                                  */
12419                                                 GET_BBLOCK (cfg, tblock, cfg->cil_start + clause->handler_offset + clause->handler_len - 1);
12420                                                 GET_BBLOCK (cfg, target_bb, target);
12421                                                 link_bblock (cfg, tblock, target_bb);
12422                                         }
12423                                 }
12424                                 g_list_free (handlers);
12425                         } 
12426
12427                         MONO_INST_NEW (cfg, ins, OP_BR);
12428                         MONO_ADD_INS (cfg->cbb, ins);
12429                         GET_BBLOCK (cfg, tblock, target);
12430                         link_bblock (cfg, cfg->cbb, tblock);
12431                         ins->inst_target_bb = tblock;
12432
12433                         start_new_bblock = 1;
12434
12435                         if (*ip == CEE_LEAVE)
12436                                 ip += 5;
12437                         else
12438                                 ip += 2;
12439
12440                         break;
12441                 }
12442
12443                         /*
12444                          * Mono specific opcodes
12445                          */
12446                 case MONO_CUSTOM_PREFIX: {
12447
12448                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
12449
12450                         CHECK_OPSIZE (2);
12451                         switch (ip [1]) {
12452                         case CEE_MONO_ICALL: {
12453                                 gpointer func;
12454                                 MonoJitICallInfo *info;
12455
12456                                 token = read32 (ip + 2);
12457                                 func = mono_method_get_wrapper_data (method, token);
12458                                 info = mono_find_jit_icall_by_addr (func);
12459                                 if (!info)
12460                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
12461                                 g_assert (info);
12462
12463                                 CHECK_STACK (info->sig->param_count);
12464                                 sp -= info->sig->param_count;
12465
12466                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
12467                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
12468                                         *sp++ = ins;
12469
12470                                 ip += 6;
12471                                 inline_costs += 10 * num_calls++;
12472
12473                                 break;
12474                         }
12475                         case CEE_MONO_LDPTR_CARD_TABLE:
12476                         case CEE_MONO_LDPTR_NURSERY_START:
12477                         case CEE_MONO_LDPTR_NURSERY_BITS:
12478                         case CEE_MONO_LDPTR_INT_REQ_FLAG: {
12479                                 CHECK_STACK_OVF (1);
12480
12481                                 switch (ip [1]) {
12482                                         case CEE_MONO_LDPTR_CARD_TABLE:
12483                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
12484                                                 break;
12485                                         case CEE_MONO_LDPTR_NURSERY_START:
12486                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_START, NULL);
12487                                                 break;
12488                                         case CEE_MONO_LDPTR_NURSERY_BITS:
12489                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_BITS, NULL);
12490                                                 break;
12491                                         case CEE_MONO_LDPTR_INT_REQ_FLAG:
12492                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
12493                                                 break;
12494                                 }
12495
12496                                 *sp++ = ins;
12497                                 ip += 2;
12498                                 inline_costs += 10 * num_calls++;
12499                                 break;
12500                         }
12501                         case CEE_MONO_LDPTR: {
12502                                 gpointer ptr;
12503
12504                                 CHECK_STACK_OVF (1);
12505                                 CHECK_OPSIZE (6);
12506                                 token = read32 (ip + 2);
12507
12508                                 ptr = mono_method_get_wrapper_data (method, token);
12509                                 EMIT_NEW_PCONST (cfg, ins, ptr);
12510                                 *sp++ = ins;
12511                                 ip += 6;
12512                                 inline_costs += 10 * num_calls++;
12513                                 /* Can't embed random pointers into AOT code */
12514                                 DISABLE_AOT (cfg);
12515                                 break;
12516                         }
12517                         case CEE_MONO_JIT_ICALL_ADDR: {
12518                                 MonoJitICallInfo *callinfo;
12519                                 gpointer ptr;
12520
12521                                 CHECK_STACK_OVF (1);
12522                                 CHECK_OPSIZE (6);
12523                                 token = read32 (ip + 2);
12524
12525                                 ptr = mono_method_get_wrapper_data (method, token);
12526                                 callinfo = mono_find_jit_icall_by_addr (ptr);
12527                                 g_assert (callinfo);
12528                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
12529                                 *sp++ = ins;
12530                                 ip += 6;
12531                                 inline_costs += 10 * num_calls++;
12532                                 break;
12533                         }
12534                         case CEE_MONO_ICALL_ADDR: {
12535                                 MonoMethod *cmethod;
12536                                 gpointer ptr;
12537
12538                                 CHECK_STACK_OVF (1);
12539                                 CHECK_OPSIZE (6);
12540                                 token = read32 (ip + 2);
12541
12542                                 cmethod = (MonoMethod *)mono_method_get_wrapper_data (method, token);
12543
12544                                 if (cfg->compile_aot) {
12545                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
12546                                 } else {
12547                                         ptr = mono_lookup_internal_call (cmethod);
12548                                         g_assert (ptr);
12549                                         EMIT_NEW_PCONST (cfg, ins, ptr);
12550                                 }
12551                                 *sp++ = ins;
12552                                 ip += 6;
12553                                 break;
12554                         }
12555                         case CEE_MONO_VTADDR: {
12556                                 MonoInst *src_var, *src;
12557
12558                                 CHECK_STACK (1);
12559                                 --sp;
12560
12561                                 // FIXME:
12562                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12563                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
12564                                 *sp++ = src;
12565                                 ip += 2;
12566                                 break;
12567                         }
12568                         case CEE_MONO_NEWOBJ: {
12569                                 MonoInst *iargs [2];
12570
12571                                 CHECK_STACK_OVF (1);
12572                                 CHECK_OPSIZE (6);
12573                                 token = read32 (ip + 2);
12574                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12575                                 mono_class_init (klass);
12576                                 NEW_DOMAINCONST (cfg, iargs [0]);
12577                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
12578                                 NEW_CLASSCONST (cfg, iargs [1], klass);
12579                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
12580                                 *sp++ = mono_emit_jit_icall (cfg, ves_icall_object_new, iargs);
12581                                 ip += 6;
12582                                 inline_costs += 10 * num_calls++;
12583                                 break;
12584                         }
12585                         case CEE_MONO_OBJADDR:
12586                                 CHECK_STACK (1);
12587                                 --sp;
12588                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
12589                                 ins->dreg = alloc_ireg_mp (cfg);
12590                                 ins->sreg1 = sp [0]->dreg;
12591                                 ins->type = STACK_MP;
12592                                 MONO_ADD_INS (cfg->cbb, ins);
12593                                 *sp++ = ins;
12594                                 ip += 2;
12595                                 break;
12596                         case CEE_MONO_LDNATIVEOBJ:
12597                                 /*
12598                                  * Similar to LDOBJ, but instead load the unmanaged 
12599                                  * representation of the vtype to the stack.
12600                                  */
12601                                 CHECK_STACK (1);
12602                                 CHECK_OPSIZE (6);
12603                                 --sp;
12604                                 token = read32 (ip + 2);
12605                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12606                                 g_assert (klass->valuetype);
12607                                 mono_class_init (klass);
12608
12609                                 {
12610                                         MonoInst *src, *dest, *temp;
12611
12612                                         src = sp [0];
12613                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
12614                                         temp->backend.is_pinvoke = 1;
12615                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
12616                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
12617
12618                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
12619                                         dest->type = STACK_VTYPE;
12620                                         dest->klass = klass;
12621
12622                                         *sp ++ = dest;
12623                                         ip += 6;
12624                                 }
12625                                 break;
12626                         case CEE_MONO_RETOBJ: {
12627                                 /*
12628                                  * Same as RET, but return the native representation of a vtype
12629                                  * to the caller.
12630                                  */
12631                                 g_assert (cfg->ret);
12632                                 g_assert (mono_method_signature (method)->pinvoke); 
12633                                 CHECK_STACK (1);
12634                                 --sp;
12635                                 
12636                                 CHECK_OPSIZE (6);
12637                                 token = read32 (ip + 2);    
12638                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12639
12640                                 if (!cfg->vret_addr) {
12641                                         g_assert (cfg->ret_var_is_local);
12642
12643                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
12644                                 } else {
12645                                         EMIT_NEW_RETLOADA (cfg, ins);
12646                                 }
12647                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
12648                                 
12649                                 if (sp != stack_start)
12650                                         UNVERIFIED;
12651                                 
12652                                 MONO_INST_NEW (cfg, ins, OP_BR);
12653                                 ins->inst_target_bb = end_bblock;
12654                                 MONO_ADD_INS (cfg->cbb, ins);
12655                                 link_bblock (cfg, cfg->cbb, end_bblock);
12656                                 start_new_bblock = 1;
12657                                 ip += 6;
12658                                 break;
12659                         }
12660                         case CEE_MONO_CISINST:
12661                         case CEE_MONO_CCASTCLASS: {
12662                                 int token;
12663                                 CHECK_STACK (1);
12664                                 --sp;
12665                                 CHECK_OPSIZE (6);
12666                                 token = read32 (ip + 2);
12667                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12668                                 if (ip [1] == CEE_MONO_CISINST)
12669                                         ins = handle_cisinst (cfg, klass, sp [0]);
12670                                 else
12671                                         ins = handle_ccastclass (cfg, klass, sp [0]);
12672                                 *sp++ = ins;
12673                                 ip += 6;
12674                                 break;
12675                         }
12676                         case CEE_MONO_SAVE_LMF:
12677                         case CEE_MONO_RESTORE_LMF:
12678                                 ip += 2;
12679                                 break;
12680                         case CEE_MONO_CLASSCONST:
12681                                 CHECK_STACK_OVF (1);
12682                                 CHECK_OPSIZE (6);
12683                                 token = read32 (ip + 2);
12684                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
12685                                 *sp++ = ins;
12686                                 ip += 6;
12687                                 inline_costs += 10 * num_calls++;
12688                                 break;
12689                         case CEE_MONO_NOT_TAKEN:
12690                                 cfg->cbb->out_of_line = TRUE;
12691                                 ip += 2;
12692                                 break;
12693                         case CEE_MONO_TLS: {
12694                                 MonoTlsKey key;
12695
12696                                 CHECK_STACK_OVF (1);
12697                                 CHECK_OPSIZE (6);
12698                                 key = (MonoTlsKey)read32 (ip + 2);
12699                                 g_assert (key < TLS_KEY_NUM);
12700
12701                                 ins = mono_create_tls_get (cfg, key);
12702                                 if (!ins) {
12703                                         if (cfg->compile_aot) {
12704                                                 DISABLE_AOT (cfg);
12705                                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
12706                                                 ins->dreg = alloc_preg (cfg);
12707                                                 ins->type = STACK_PTR;
12708                                         } else {
12709                                                 g_assert_not_reached ();
12710                                         }
12711                                 }
12712                                 ins->type = STACK_PTR;
12713                                 MONO_ADD_INS (cfg->cbb, ins);
12714                                 *sp++ = ins;
12715                                 ip += 6;
12716                                 break;
12717                         }
12718                         case CEE_MONO_DYN_CALL: {
12719                                 MonoCallInst *call;
12720
12721                                 /* It would be easier to call a trampoline, but that would put an
12722                                  * extra frame on the stack, confusing exception handling. So
12723                                  * implement it inline using an opcode for now.
12724                                  */
12725
12726                                 if (!cfg->dyn_call_var) {
12727                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12728                                         /* prevent it from being register allocated */
12729                                         cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
12730                                 }
12731
12732                                 /* Has to use a call inst since it local regalloc expects it */
12733                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
12734                                 ins = (MonoInst*)call;
12735                                 sp -= 2;
12736                                 ins->sreg1 = sp [0]->dreg;
12737                                 ins->sreg2 = sp [1]->dreg;
12738                                 MONO_ADD_INS (cfg->cbb, ins);
12739
12740                                 cfg->param_area = MAX (cfg->param_area, cfg->backend->dyn_call_param_area);
12741
12742                                 ip += 2;
12743                                 inline_costs += 10 * num_calls++;
12744
12745                                 break;
12746                         }
12747                         case CEE_MONO_MEMORY_BARRIER: {
12748                                 CHECK_OPSIZE (6);
12749                                 emit_memory_barrier (cfg, (int)read32 (ip + 2));
12750                                 ip += 6;
12751                                 break;
12752                         }
12753                         case CEE_MONO_JIT_ATTACH: {
12754                                 MonoInst *args [16], *domain_ins;
12755                                 MonoInst *ad_ins, *jit_tls_ins;
12756                                 MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
12757
12758                                 cfg->attach_cookie = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12759                                 cfg->attach_dummy = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12760
12761                                 if (mono_threads_is_coop_enabled ()) {
12762                                         /* AOT code is only used in the root domain */
12763                                         EMIT_NEW_PCONST (cfg, args [0], cfg->compile_aot ? NULL : cfg->domain);
12764                                         EMIT_NEW_VARLOADA (cfg, args [1], cfg->attach_dummy, cfg->attach_dummy->inst_vtype);
12765                                         ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
12766                                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->attach_cookie->dreg, ins->dreg);
12767                                 } else {
12768                                         EMIT_NEW_PCONST (cfg, ins, NULL);
12769                                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->attach_cookie->dreg, ins->dreg);
12770
12771                                         ad_ins = mono_get_domain_intrinsic (cfg);
12772                                         jit_tls_ins = mono_get_jit_tls_intrinsic (cfg);
12773
12774                                         if (cfg->backend->have_tls_get && ad_ins && jit_tls_ins) {
12775                                                 NEW_BBLOCK (cfg, next_bb);
12776                                                 NEW_BBLOCK (cfg, call_bb);
12777
12778                                                 if (cfg->compile_aot) {
12779                                                         /* AOT code is only used in the root domain */
12780                                                         EMIT_NEW_PCONST (cfg, domain_ins, NULL);
12781                                                 } else {
12782                                                         EMIT_NEW_PCONST (cfg, domain_ins, cfg->domain);
12783                                                 }
12784                                                 MONO_ADD_INS (cfg->cbb, ad_ins);
12785                                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg);
12786                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb);
12787
12788                                                 MONO_ADD_INS (cfg->cbb, jit_tls_ins);
12789                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0);
12790                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb);
12791
12792                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb);
12793                                                 MONO_START_BB (cfg, call_bb);
12794                                         }
12795
12796                                         /* AOT code is only used in the root domain */
12797                                         EMIT_NEW_PCONST (cfg, args [0], cfg->compile_aot ? NULL : cfg->domain);
12798                                         EMIT_NEW_PCONST (cfg, args [1], NULL);
12799                                         ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
12800                                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->attach_cookie->dreg, ins->dreg);
12801
12802                                         if (next_bb)
12803                                                 MONO_START_BB (cfg, next_bb);
12804                                 }
12805
12806                                 ip += 2;
12807                                 break;
12808                         }
12809                         case CEE_MONO_JIT_DETACH: {
12810                                 MonoInst *args [16];
12811
12812                                 /* Restore the original domain */
12813                                 dreg = alloc_ireg (cfg);
12814                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->attach_cookie->dreg);
12815                                 EMIT_NEW_VARLOADA (cfg, args [1], cfg->attach_dummy, cfg->attach_dummy->inst_vtype);
12816                                 mono_emit_jit_icall (cfg, mono_jit_thread_detach, args);
12817                                 ip += 2;
12818                                 break;
12819                         }
12820                         case CEE_MONO_CALLI_EXTRA_ARG: {
12821                                 MonoInst *addr;
12822                                 MonoMethodSignature *fsig;
12823                                 MonoInst *arg;
12824
12825                                 /*
12826                                  * This is the same as CEE_CALLI, but passes an additional argument
12827                                  * to the called method in llvmonly mode.
12828                                  * This is only used by delegate invoke wrappers to call the
12829                                  * actual delegate method.
12830                                  */
12831                                 g_assert (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE);
12832
12833                                 CHECK_OPSIZE (6);
12834                                 token = read32 (ip + 2);
12835
12836                                 ins = NULL;
12837
12838                                 cmethod = NULL;
12839                                 CHECK_STACK (1);
12840                                 --sp;
12841                                 addr = *sp;
12842                                 fsig = mini_get_signature (method, token, generic_context);
12843
12844                                 if (cfg->llvm_only)
12845                                         cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
12846
12847                                 n = fsig->param_count + fsig->hasthis + 1;
12848
12849                                 CHECK_STACK (n);
12850
12851                                 sp -= n;
12852                                 arg = sp [n - 1];
12853
12854                                 if (cfg->llvm_only) {
12855                                         /*
12856                                          * The lowest bit of 'arg' determines whenever the callee uses the gsharedvt
12857                                          * cconv. This is set by mono_init_delegate ().
12858                                          */
12859                                         if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig)) {
12860                                                 MonoInst *callee = addr;
12861                                                 MonoInst *call, *localloc_ins;
12862                                                 MonoBasicBlock *is_gsharedvt_bb, *end_bb;
12863                                                 int low_bit_reg = alloc_preg (cfg);
12864
12865                                                 NEW_BBLOCK (cfg, is_gsharedvt_bb);
12866                                                 NEW_BBLOCK (cfg, end_bb);
12867
12868                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
12869                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
12870                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
12871
12872                                                 /* Normal case: callee uses a normal cconv, have to add an out wrapper */
12873                                                 addr = emit_get_rgctx_sig (cfg, context_used,
12874                                                                                                    fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
12875                                                 /*
12876                                                  * ADDR points to a gsharedvt-out wrapper, have to pass <callee, arg> as an extra arg.
12877                                                  */
12878                                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
12879                                                 ins->dreg = alloc_preg (cfg);
12880                                                 ins->inst_imm = 2 * SIZEOF_VOID_P;
12881                                                 MONO_ADD_INS (cfg->cbb, ins);
12882                                                 localloc_ins = ins;
12883                                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12884                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
12885                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
12886
12887                                                 call = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
12888                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12889
12890                                                 /* Gsharedvt case: callee uses a gsharedvt cconv, no conversion is needed */
12891                                                 MONO_START_BB (cfg, is_gsharedvt_bb);
12892                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
12893                                                 ins = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
12894                                                 ins->dreg = call->dreg;
12895
12896                                                 MONO_START_BB (cfg, end_bb);
12897                                         } else {
12898                                                 /* Caller uses a normal calling conv */
12899
12900                                                 MonoInst *callee = addr;
12901                                                 MonoInst *call, *localloc_ins;
12902                                                 MonoBasicBlock *is_gsharedvt_bb, *end_bb;
12903                                                 int low_bit_reg = alloc_preg (cfg);
12904
12905                                                 NEW_BBLOCK (cfg, is_gsharedvt_bb);
12906                                                 NEW_BBLOCK (cfg, end_bb);
12907
12908                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
12909                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
12910                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
12911
12912                                                 /* Normal case: callee uses a normal cconv, no conversion is needed */
12913                                                 call = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
12914                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12915                                                 /* Gsharedvt case: callee uses a gsharedvt cconv, have to add an in wrapper */
12916                                                 MONO_START_BB (cfg, is_gsharedvt_bb);
12917                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
12918                                                 NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER, fsig);
12919                                                 MONO_ADD_INS (cfg->cbb, addr);
12920                                                 /*
12921                                                  * ADDR points to a gsharedvt-in wrapper, have to pass <callee, arg> as an extra arg.
12922                                                  */
12923                                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
12924                                                 ins->dreg = alloc_preg (cfg);
12925                                                 ins->inst_imm = 2 * SIZEOF_VOID_P;
12926                                                 MONO_ADD_INS (cfg->cbb, ins);
12927                                                 localloc_ins = ins;
12928                                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12929                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
12930                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
12931
12932                                                 ins = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
12933                                                 ins->dreg = call->dreg;
12934                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
12935
12936                                                 MONO_START_BB (cfg, end_bb);
12937                                         }
12938                                 } else {
12939                                         /* Same as CEE_CALLI */
12940                                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
12941                                                 /*
12942                                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
12943                                                  */
12944                                                 MonoInst *callee = addr;
12945
12946                                                 addr = emit_get_rgctx_sig (cfg, context_used,
12947                                                                                                    fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
12948                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
12949                                         } else {
12950                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
12951                                         }
12952                                 }
12953
12954                                 if (!MONO_TYPE_IS_VOID (fsig->ret))
12955                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
12956
12957                                 CHECK_CFG_EXCEPTION;
12958
12959                                 ip += 6;
12960                                 ins_flag = 0;
12961                                 constrained_class = NULL;
12962                                 break;
12963                         }
12964                         default:
12965                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
12966                                 break;
12967                         }
12968                         break;
12969                 }
12970
12971                 case CEE_PREFIX1: {
12972                         CHECK_OPSIZE (2);
12973                         switch (ip [1]) {
12974                         case CEE_ARGLIST: {
12975                                 /* somewhat similar to LDTOKEN */
12976                                 MonoInst *addr, *vtvar;
12977                                 CHECK_STACK_OVF (1);
12978                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
12979
12980                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12981                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
12982
12983                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12984                                 ins->type = STACK_VTYPE;
12985                                 ins->klass = mono_defaults.argumenthandle_class;
12986                                 *sp++ = ins;
12987                                 ip += 2;
12988                                 break;
12989                         }
12990                         case CEE_CEQ:
12991                         case CEE_CGT:
12992                         case CEE_CGT_UN:
12993                         case CEE_CLT:
12994                         case CEE_CLT_UN: {
12995                                 MonoInst *cmp, *arg1, *arg2;
12996
12997                                 CHECK_STACK (2);
12998                                 sp -= 2;
12999                                 arg1 = sp [0];
13000                                 arg2 = sp [1];
13001
13002                                 /*
13003                                  * The following transforms:
13004                                  *    CEE_CEQ    into OP_CEQ
13005                                  *    CEE_CGT    into OP_CGT
13006                                  *    CEE_CGT_UN into OP_CGT_UN
13007                                  *    CEE_CLT    into OP_CLT
13008                                  *    CEE_CLT_UN into OP_CLT_UN
13009                                  */
13010                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
13011
13012                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
13013                                 cmp->sreg1 = arg1->dreg;
13014                                 cmp->sreg2 = arg2->dreg;
13015                                 type_from_op (cfg, cmp, arg1, arg2);
13016                                 CHECK_TYPE (cmp);
13017                                 add_widen_op (cfg, cmp, &arg1, &arg2);
13018                                 if ((arg1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((arg1->type == STACK_PTR) || (arg1->type == STACK_OBJ) || (arg1->type == STACK_MP))))
13019                                         cmp->opcode = OP_LCOMPARE;
13020                                 else if (arg1->type == STACK_R4)
13021                                         cmp->opcode = OP_RCOMPARE;
13022                                 else if (arg1->type == STACK_R8)
13023                                         cmp->opcode = OP_FCOMPARE;
13024                                 else
13025                                         cmp->opcode = OP_ICOMPARE;
13026                                 MONO_ADD_INS (cfg->cbb, cmp);
13027                                 ins->type = STACK_I4;
13028                                 ins->dreg = alloc_dreg (cfg, (MonoStackType)ins->type);
13029                                 type_from_op (cfg, ins, arg1, arg2);
13030
13031                                 if (cmp->opcode == OP_FCOMPARE || cmp->opcode == OP_RCOMPARE) {
13032                                         /*
13033                                          * The backends expect the fceq opcodes to do the
13034                                          * comparison too.
13035                                          */
13036                                         ins->sreg1 = cmp->sreg1;
13037                                         ins->sreg2 = cmp->sreg2;
13038                                         NULLIFY_INS (cmp);
13039                                 }
13040                                 MONO_ADD_INS (cfg->cbb, ins);
13041                                 *sp++ = ins;
13042                                 ip += 2;
13043                                 break;
13044                         }
13045                         case CEE_LDFTN: {
13046                                 MonoInst *argconst;
13047                                 MonoMethod *cil_method;
13048
13049                                 CHECK_STACK_OVF (1);
13050                                 CHECK_OPSIZE (6);
13051                                 n = read32 (ip + 2);
13052                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
13053                                 CHECK_CFG_ERROR;
13054
13055                                 mono_class_init (cmethod->klass);
13056
13057                                 mono_save_token_info (cfg, image, n, cmethod);
13058
13059                                 context_used = mini_method_check_context_used (cfg, cmethod);
13060
13061                                 cil_method = cmethod;
13062                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
13063                                         METHOD_ACCESS_FAILURE (method, cil_method);
13064
13065                                 if (mono_security_core_clr_enabled ())
13066                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
13067
13068                                 /* 
13069                                  * Optimize the common case of ldftn+delegate creation
13070                                  */
13071                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
13072                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
13073                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
13074                                                 MonoInst *target_ins, *handle_ins;
13075                                                 MonoMethod *invoke;
13076                                                 int invoke_context_used;
13077
13078                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
13079                                                 if (!invoke || !mono_method_signature (invoke))
13080                                                         LOAD_ERROR;
13081
13082                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
13083
13084                                                 target_ins = sp [-1];
13085
13086                                                 if (mono_security_core_clr_enabled ())
13087                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
13088
13089                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
13090                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
13091                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
13092                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
13093                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
13094                                                         }
13095                                                 }
13096
13097                                                 /* FIXME: SGEN support */
13098                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
13099                                                         ip += 6;
13100                                                         if (cfg->verbose_level > 3)
13101                                                                 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));
13102                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, FALSE))) {
13103                                                                 sp --;
13104                                                                 *sp = handle_ins;
13105                                                                 CHECK_CFG_EXCEPTION;
13106                                                                 ip += 5;
13107                                                                 sp ++;
13108                                                                 break;
13109                                                         }
13110                                                         ip -= 6;
13111                                                 }
13112                                         }
13113                                 }
13114
13115                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
13116                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
13117                                 *sp++ = ins;
13118                                 
13119                                 ip += 6;
13120                                 inline_costs += 10 * num_calls++;
13121                                 break;
13122                         }
13123                         case CEE_LDVIRTFTN: {
13124                                 MonoInst *args [2];
13125
13126                                 CHECK_STACK (1);
13127                                 CHECK_OPSIZE (6);
13128                                 n = read32 (ip + 2);
13129                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
13130                                 CHECK_CFG_ERROR;
13131
13132                                 mono_class_init (cmethod->klass);
13133  
13134                                 context_used = mini_method_check_context_used (cfg, cmethod);
13135
13136                                 if (mono_security_core_clr_enabled ())
13137                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
13138
13139                                 /*
13140                                  * Optimize the common case of ldvirtftn+delegate creation
13141                                  */
13142                                 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)) {
13143                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
13144                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
13145                                                 MonoInst *target_ins, *handle_ins;
13146                                                 MonoMethod *invoke;
13147                                                 int invoke_context_used;
13148                                                 gboolean is_virtual = cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL;
13149
13150                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
13151                                                 if (!invoke || !mono_method_signature (invoke))
13152                                                         LOAD_ERROR;
13153
13154                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
13155
13156                                                 target_ins = sp [-1];
13157
13158                                                 if (mono_security_core_clr_enabled ())
13159                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
13160
13161                                                 /* FIXME: SGEN support */
13162                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
13163                                                         ip += 6;
13164                                                         if (cfg->verbose_level > 3)
13165                                                                 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));
13166                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, is_virtual))) {
13167                                                                 sp -= 2;
13168                                                                 *sp = handle_ins;
13169                                                                 CHECK_CFG_EXCEPTION;
13170                                                                 ip += 5;
13171                                                                 sp ++;
13172                                                                 break;
13173                                                         }
13174                                                         ip -= 6;
13175                                                 }
13176                                         }
13177                                 }
13178
13179                                 --sp;
13180                                 args [0] = *sp;
13181
13182                                 args [1] = emit_get_rgctx_method (cfg, context_used,
13183                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
13184
13185                                 if (context_used)
13186                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
13187                                 else
13188                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
13189
13190                                 ip += 6;
13191                                 inline_costs += 10 * num_calls++;
13192                                 break;
13193                         }
13194                         case CEE_LDARG:
13195                                 CHECK_STACK_OVF (1);
13196                                 CHECK_OPSIZE (4);
13197                                 n = read16 (ip + 2);
13198                                 CHECK_ARG (n);
13199                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
13200                                 *sp++ = ins;
13201                                 ip += 4;
13202                                 break;
13203                         case CEE_LDARGA:
13204                                 CHECK_STACK_OVF (1);
13205                                 CHECK_OPSIZE (4);
13206                                 n = read16 (ip + 2);
13207                                 CHECK_ARG (n);
13208                                 NEW_ARGLOADA (cfg, ins, n);
13209                                 MONO_ADD_INS (cfg->cbb, ins);
13210                                 *sp++ = ins;
13211                                 ip += 4;
13212                                 break;
13213                         case CEE_STARG:
13214                                 CHECK_STACK (1);
13215                                 --sp;
13216                                 CHECK_OPSIZE (4);
13217                                 n = read16 (ip + 2);
13218                                 CHECK_ARG (n);
13219                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
13220                                         UNVERIFIED;
13221                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
13222                                 ip += 4;
13223                                 break;
13224                         case CEE_LDLOC:
13225                                 CHECK_STACK_OVF (1);
13226                                 CHECK_OPSIZE (4);
13227                                 n = read16 (ip + 2);
13228                                 CHECK_LOCAL (n);
13229                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
13230                                 *sp++ = ins;
13231                                 ip += 4;
13232                                 break;
13233                         case CEE_LDLOCA: {
13234                                 unsigned char *tmp_ip;
13235                                 CHECK_STACK_OVF (1);
13236                                 CHECK_OPSIZE (4);
13237                                 n = read16 (ip + 2);
13238                                 CHECK_LOCAL (n);
13239
13240                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
13241                                         ip = tmp_ip;
13242                                         inline_costs += 1;
13243                                         break;
13244                                 }                       
13245                                 
13246                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
13247                                 *sp++ = ins;
13248                                 ip += 4;
13249                                 break;
13250                         }
13251                         case CEE_STLOC:
13252                                 CHECK_STACK (1);
13253                                 --sp;
13254                                 CHECK_OPSIZE (4);
13255                                 n = read16 (ip + 2);
13256                                 CHECK_LOCAL (n);
13257                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
13258                                         UNVERIFIED;
13259                                 emit_stloc_ir (cfg, sp, header, n);
13260                                 ip += 4;
13261                                 inline_costs += 1;
13262                                 break;
13263                         case CEE_LOCALLOC:
13264                                 CHECK_STACK (1);
13265                                 --sp;
13266                                 if (sp != stack_start) 
13267                                         UNVERIFIED;
13268                                 if (cfg->method != method) 
13269                                         /* 
13270                                          * Inlining this into a loop in a parent could lead to 
13271                                          * stack overflows which is different behavior than the
13272                                          * non-inlined case, thus disable inlining in this case.
13273                                          */
13274                                         INLINE_FAILURE("localloc");
13275
13276                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
13277                                 ins->dreg = alloc_preg (cfg);
13278                                 ins->sreg1 = sp [0]->dreg;
13279                                 ins->type = STACK_PTR;
13280                                 MONO_ADD_INS (cfg->cbb, ins);
13281
13282                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
13283                                 if (init_locals)
13284                                         ins->flags |= MONO_INST_INIT;
13285
13286                                 *sp++ = ins;
13287                                 ip += 2;
13288                                 break;
13289                         case CEE_ENDFILTER: {
13290                                 MonoExceptionClause *clause, *nearest;
13291                                 int cc;
13292
13293                                 CHECK_STACK (1);
13294                                 --sp;
13295                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
13296                                         UNVERIFIED;
13297                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
13298                                 ins->sreg1 = (*sp)->dreg;
13299                                 MONO_ADD_INS (cfg->cbb, ins);
13300                                 start_new_bblock = 1;
13301                                 ip += 2;
13302
13303                                 nearest = NULL;
13304                                 for (cc = 0; cc < header->num_clauses; ++cc) {
13305                                         clause = &header->clauses [cc];
13306                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
13307                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
13308                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset)))
13309                                                 nearest = clause;
13310                                 }
13311                                 g_assert (nearest);
13312                                 if ((ip - header->code) != nearest->handler_offset)
13313                                         UNVERIFIED;
13314
13315                                 break;
13316                         }
13317                         case CEE_UNALIGNED_:
13318                                 ins_flag |= MONO_INST_UNALIGNED;
13319                                 /* FIXME: record alignment? we can assume 1 for now */
13320                                 CHECK_OPSIZE (3);
13321                                 ip += 3;
13322                                 break;
13323                         case CEE_VOLATILE_:
13324                                 ins_flag |= MONO_INST_VOLATILE;
13325                                 ip += 2;
13326                                 break;
13327                         case CEE_TAIL_:
13328                                 ins_flag   |= MONO_INST_TAILCALL;
13329                                 cfg->flags |= MONO_CFG_HAS_TAIL;
13330                                 /* Can't inline tail calls at this time */
13331                                 inline_costs += 100000;
13332                                 ip += 2;
13333                                 break;
13334                         case CEE_INITOBJ:
13335                                 CHECK_STACK (1);
13336                                 --sp;
13337                                 CHECK_OPSIZE (6);
13338                                 token = read32 (ip + 2);
13339                                 klass = mini_get_class (method, token, generic_context);
13340                                 CHECK_TYPELOAD (klass);
13341                                 if (generic_class_is_reference_type (cfg, klass))
13342                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
13343                                 else
13344                                         mini_emit_initobj (cfg, *sp, NULL, klass);
13345                                 ip += 6;
13346                                 inline_costs += 1;
13347                                 break;
13348                         case CEE_CONSTRAINED_:
13349                                 CHECK_OPSIZE (6);
13350                                 token = read32 (ip + 2);
13351                                 constrained_class = mini_get_class (method, token, generic_context);
13352                                 CHECK_TYPELOAD (constrained_class);
13353                                 ip += 6;
13354                                 break;
13355                         case CEE_CPBLK:
13356                         case CEE_INITBLK: {
13357                                 MonoInst *iargs [3];
13358                                 CHECK_STACK (3);
13359                                 sp -= 3;
13360
13361                                 /* Skip optimized paths for volatile operations. */
13362                                 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)) {
13363                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
13364                                 } 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)) {
13365                                         /* emit_memset only works when val == 0 */
13366                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
13367                                 } else {
13368                                         MonoInst *call;
13369                                         iargs [0] = sp [0];
13370                                         iargs [1] = sp [1];
13371                                         iargs [2] = sp [2];
13372                                         if (ip [1] == CEE_CPBLK) {
13373                                                 /*
13374                                                  * FIXME: It's unclear whether we should be emitting both the acquire
13375                                                  * and release barriers for cpblk. It is technically both a load and
13376                                                  * store operation, so it seems like that's the sensible thing to do.
13377                                                  *
13378                                                  * FIXME: We emit full barriers on both sides of the operation for
13379                                                  * simplicity. We should have a separate atomic memcpy method instead.
13380                                                  */
13381                                                 MonoMethod *memcpy_method = get_memcpy_method ();
13382
13383                                                 if (ins_flag & MONO_INST_VOLATILE)
13384                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
13385
13386                                                 call = mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
13387                                                 call->flags |= ins_flag;
13388
13389                                                 if (ins_flag & MONO_INST_VOLATILE)
13390                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
13391                                         } else {
13392                                                 MonoMethod *memset_method = get_memset_method ();
13393                                                 if (ins_flag & MONO_INST_VOLATILE) {
13394                                                         /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
13395                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
13396                                                 }
13397                                                 call = mono_emit_method_call (cfg, memset_method, iargs, NULL);
13398                                                 call->flags |= ins_flag;
13399                                         }
13400                                 }
13401                                 ip += 2;
13402                                 ins_flag = 0;
13403                                 inline_costs += 1;
13404                                 break;
13405                         }
13406                         case CEE_NO_:
13407                                 CHECK_OPSIZE (3);
13408                                 if (ip [2] & 0x1)
13409                                         ins_flag |= MONO_INST_NOTYPECHECK;
13410                                 if (ip [2] & 0x2)
13411                                         ins_flag |= MONO_INST_NORANGECHECK;
13412                                 /* we ignore the no-nullcheck for now since we
13413                                  * really do it explicitly only when doing callvirt->call
13414                                  */
13415                                 ip += 3;
13416                                 break;
13417                         case CEE_RETHROW: {
13418                                 MonoInst *load;
13419                                 int handler_offset = -1;
13420
13421                                 for (i = 0; i < header->num_clauses; ++i) {
13422                                         MonoExceptionClause *clause = &header->clauses [i];
13423                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
13424                                                 handler_offset = clause->handler_offset;
13425                                                 break;
13426                                         }
13427                                 }
13428
13429                                 cfg->cbb->flags |= BB_EXCEPTION_UNSAFE;
13430
13431                                 if (handler_offset == -1)
13432                                         UNVERIFIED;
13433
13434                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
13435                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
13436                                 ins->sreg1 = load->dreg;
13437                                 MONO_ADD_INS (cfg->cbb, ins);
13438
13439                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
13440                                 MONO_ADD_INS (cfg->cbb, ins);
13441
13442                                 sp = stack_start;
13443                                 link_bblock (cfg, cfg->cbb, end_bblock);
13444                                 start_new_bblock = 1;
13445                                 ip += 2;
13446                                 break;
13447                         }
13448                         case CEE_SIZEOF: {
13449                                 guint32 val;
13450                                 int ialign;
13451
13452                                 CHECK_STACK_OVF (1);
13453                                 CHECK_OPSIZE (6);
13454                                 token = read32 (ip + 2);
13455                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !image_is_dynamic (method->klass->image) && !generic_context) {
13456                                         MonoType *type = mono_type_create_from_typespec_checked (image, token, &cfg->error);
13457                                         CHECK_CFG_ERROR;
13458
13459                                         val = mono_type_size (type, &ialign);
13460                                 } else {
13461                                         MonoClass *klass = mini_get_class (method, token, generic_context);
13462                                         CHECK_TYPELOAD (klass);
13463
13464                                         val = mono_type_size (&klass->byval_arg, &ialign);
13465
13466                                         if (mini_is_gsharedvt_klass (klass))
13467                                                 GSHAREDVT_FAILURE (*ip);
13468                                 }
13469                                 EMIT_NEW_ICONST (cfg, ins, val);
13470                                 *sp++= ins;
13471                                 ip += 6;
13472                                 break;
13473                         }
13474                         case CEE_REFANYTYPE: {
13475                                 MonoInst *src_var, *src;
13476
13477                                 GSHAREDVT_FAILURE (*ip);
13478
13479                                 CHECK_STACK (1);
13480                                 --sp;
13481
13482                                 // FIXME:
13483                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
13484                                 if (!src_var)
13485                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
13486                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
13487                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type));
13488                                 *sp++ = ins;
13489                                 ip += 2;
13490                                 break;
13491                         }
13492                         case CEE_READONLY_:
13493                                 readonly = TRUE;
13494                                 ip += 2;
13495                                 break;
13496
13497                         case CEE_UNUSED56:
13498                         case CEE_UNUSED57:
13499                         case CEE_UNUSED70:
13500                         case CEE_UNUSED:
13501                         case CEE_UNUSED99:
13502                                 UNVERIFIED;
13503                                 
13504                         default:
13505                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
13506                                 UNVERIFIED;
13507                         }
13508                         break;
13509                 }
13510                 case CEE_UNUSED58:
13511                 case CEE_UNUSED1:
13512                         UNVERIFIED;
13513
13514                 default:
13515                         g_warning ("opcode 0x%02x not handled", *ip);
13516                         UNVERIFIED;
13517                 }
13518         }
13519         if (start_new_bblock != 1)
13520                 UNVERIFIED;
13521
13522         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
13523         if (cfg->cbb->next_bb) {
13524                 /* This could already be set because of inlining, #693905 */
13525                 MonoBasicBlock *bb = cfg->cbb;
13526
13527                 while (bb->next_bb)
13528                         bb = bb->next_bb;
13529                 bb->next_bb = end_bblock;
13530         } else {
13531                 cfg->cbb->next_bb = end_bblock;
13532         }
13533
13534         if (cfg->method == method && cfg->domainvar) {
13535                 MonoInst *store;
13536                 MonoInst *get_domain;
13537
13538                 cfg->cbb = init_localsbb;
13539
13540                 if ((get_domain = mono_get_domain_intrinsic (cfg))) {
13541                         MONO_ADD_INS (cfg->cbb, get_domain);
13542                 } else {
13543                         get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
13544                 }
13545                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
13546                 MONO_ADD_INS (cfg->cbb, store);
13547         }
13548
13549 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
13550         if (cfg->compile_aot)
13551                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
13552                 mono_get_got_var (cfg);
13553 #endif
13554
13555         if (cfg->method == method && cfg->got_var)
13556                 mono_emit_load_got_addr (cfg);
13557
13558         if (init_localsbb) {
13559                 cfg->cbb = init_localsbb;
13560                 cfg->ip = NULL;
13561                 for (i = 0; i < header->num_locals; ++i) {
13562                         emit_init_local (cfg, i, header->locals [i], init_locals);
13563                 }
13564         }
13565
13566         if (cfg->init_ref_vars && cfg->method == method) {
13567                 /* Emit initialization for ref vars */
13568                 // FIXME: Avoid duplication initialization for IL locals.
13569                 for (i = 0; i < cfg->num_varinfo; ++i) {
13570                         MonoInst *ins = cfg->varinfo [i];
13571
13572                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
13573                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
13574                 }
13575         }
13576
13577         if (cfg->lmf_var && cfg->method == method && !cfg->llvm_only) {
13578                 cfg->cbb = init_localsbb;
13579                 emit_push_lmf (cfg);
13580         }
13581
13582         cfg->cbb = init_localsbb;
13583         emit_instrumentation_call (cfg, mono_profiler_method_enter);
13584
13585         if (seq_points) {
13586                 MonoBasicBlock *bb;
13587
13588                 /*
13589                  * Make seq points at backward branch targets interruptable.
13590                  */
13591                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
13592                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
13593                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
13594         }
13595
13596         /* Add a sequence point for method entry/exit events */
13597         if (seq_points && cfg->gen_sdb_seq_points) {
13598                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
13599                 MONO_ADD_INS (init_localsbb, ins);
13600                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
13601                 MONO_ADD_INS (cfg->bb_exit, ins);
13602         }
13603
13604         /*
13605          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
13606          * the code they refer to was dead (#11880).
13607          */
13608         if (sym_seq_points) {
13609                 for (i = 0; i < header->code_size; ++i) {
13610                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
13611                                 MonoInst *ins;
13612
13613                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
13614                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
13615                         }
13616                 }
13617         }
13618
13619         cfg->ip = NULL;
13620
13621         if (cfg->method == method) {
13622                 MonoBasicBlock *bb;
13623                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13624                         bb->region = mono_find_block_region (cfg, bb->real_offset);
13625                         if (cfg->spvars)
13626                                 mono_create_spvar_for_region (cfg, bb->region);
13627                         if (cfg->verbose_level > 2)
13628                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
13629                 }
13630         }
13631
13632         if (inline_costs < 0) {
13633                 char *mname;
13634
13635                 /* Method is too large */
13636                 mname = mono_method_full_name (method, TRUE);
13637                 mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Method %s is too complex.", mname));
13638                 g_free (mname);
13639         }
13640
13641         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
13642                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
13643
13644         goto cleanup;
13645
13646 mono_error_exit:
13647         g_assert (!mono_error_ok (&cfg->error));
13648         goto cleanup;
13649  
13650  exception_exit:
13651         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
13652         goto cleanup;
13653
13654  unverified:
13655         set_exception_type_from_invalid_il (cfg, method, ip);
13656         goto cleanup;
13657
13658  cleanup:
13659         g_slist_free (class_inits);
13660         mono_basic_block_free (original_bb);
13661         cfg->dont_inline = g_list_remove (cfg->dont_inline, method);
13662         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
13663         if (cfg->exception_type)
13664                 return -1;
13665         else
13666                 return inline_costs;
13667 }
13668
13669 static int
13670 store_membase_reg_to_store_membase_imm (int opcode)
13671 {
13672         switch (opcode) {
13673         case OP_STORE_MEMBASE_REG:
13674                 return OP_STORE_MEMBASE_IMM;
13675         case OP_STOREI1_MEMBASE_REG:
13676                 return OP_STOREI1_MEMBASE_IMM;
13677         case OP_STOREI2_MEMBASE_REG:
13678                 return OP_STOREI2_MEMBASE_IMM;
13679         case OP_STOREI4_MEMBASE_REG:
13680                 return OP_STOREI4_MEMBASE_IMM;
13681         case OP_STOREI8_MEMBASE_REG:
13682                 return OP_STOREI8_MEMBASE_IMM;
13683         default:
13684                 g_assert_not_reached ();
13685         }
13686
13687         return -1;
13688 }               
13689
13690 int
13691 mono_op_to_op_imm (int opcode)
13692 {
13693         switch (opcode) {
13694         case OP_IADD:
13695                 return OP_IADD_IMM;
13696         case OP_ISUB:
13697                 return OP_ISUB_IMM;
13698         case OP_IDIV:
13699                 return OP_IDIV_IMM;
13700         case OP_IDIV_UN:
13701                 return OP_IDIV_UN_IMM;
13702         case OP_IREM:
13703                 return OP_IREM_IMM;
13704         case OP_IREM_UN:
13705                 return OP_IREM_UN_IMM;
13706         case OP_IMUL:
13707                 return OP_IMUL_IMM;
13708         case OP_IAND:
13709                 return OP_IAND_IMM;
13710         case OP_IOR:
13711                 return OP_IOR_IMM;
13712         case OP_IXOR:
13713                 return OP_IXOR_IMM;
13714         case OP_ISHL:
13715                 return OP_ISHL_IMM;
13716         case OP_ISHR:
13717                 return OP_ISHR_IMM;
13718         case OP_ISHR_UN:
13719                 return OP_ISHR_UN_IMM;
13720
13721         case OP_LADD:
13722                 return OP_LADD_IMM;
13723         case OP_LSUB:
13724                 return OP_LSUB_IMM;
13725         case OP_LAND:
13726                 return OP_LAND_IMM;
13727         case OP_LOR:
13728                 return OP_LOR_IMM;
13729         case OP_LXOR:
13730                 return OP_LXOR_IMM;
13731         case OP_LSHL:
13732                 return OP_LSHL_IMM;
13733         case OP_LSHR:
13734                 return OP_LSHR_IMM;
13735         case OP_LSHR_UN:
13736                 return OP_LSHR_UN_IMM;
13737 #if SIZEOF_REGISTER == 8
13738         case OP_LREM:
13739                 return OP_LREM_IMM;
13740 #endif
13741
13742         case OP_COMPARE:
13743                 return OP_COMPARE_IMM;
13744         case OP_ICOMPARE:
13745                 return OP_ICOMPARE_IMM;
13746         case OP_LCOMPARE:
13747                 return OP_LCOMPARE_IMM;
13748
13749         case OP_STORE_MEMBASE_REG:
13750                 return OP_STORE_MEMBASE_IMM;
13751         case OP_STOREI1_MEMBASE_REG:
13752                 return OP_STOREI1_MEMBASE_IMM;
13753         case OP_STOREI2_MEMBASE_REG:
13754                 return OP_STOREI2_MEMBASE_IMM;
13755         case OP_STOREI4_MEMBASE_REG:
13756                 return OP_STOREI4_MEMBASE_IMM;
13757
13758 #if defined(TARGET_X86) || defined (TARGET_AMD64)
13759         case OP_X86_PUSH:
13760                 return OP_X86_PUSH_IMM;
13761         case OP_X86_COMPARE_MEMBASE_REG:
13762                 return OP_X86_COMPARE_MEMBASE_IMM;
13763 #endif
13764 #if defined(TARGET_AMD64)
13765         case OP_AMD64_ICOMPARE_MEMBASE_REG:
13766                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13767 #endif
13768         case OP_VOIDCALL_REG:
13769                 return OP_VOIDCALL;
13770         case OP_CALL_REG:
13771                 return OP_CALL;
13772         case OP_LCALL_REG:
13773                 return OP_LCALL;
13774         case OP_FCALL_REG:
13775                 return OP_FCALL;
13776         case OP_LOCALLOC:
13777                 return OP_LOCALLOC_IMM;
13778         }
13779
13780         return -1;
13781 }
13782
13783 static int
13784 ldind_to_load_membase (int opcode)
13785 {
13786         switch (opcode) {
13787         case CEE_LDIND_I1:
13788                 return OP_LOADI1_MEMBASE;
13789         case CEE_LDIND_U1:
13790                 return OP_LOADU1_MEMBASE;
13791         case CEE_LDIND_I2:
13792                 return OP_LOADI2_MEMBASE;
13793         case CEE_LDIND_U2:
13794                 return OP_LOADU2_MEMBASE;
13795         case CEE_LDIND_I4:
13796                 return OP_LOADI4_MEMBASE;
13797         case CEE_LDIND_U4:
13798                 return OP_LOADU4_MEMBASE;
13799         case CEE_LDIND_I:
13800                 return OP_LOAD_MEMBASE;
13801         case CEE_LDIND_REF:
13802                 return OP_LOAD_MEMBASE;
13803         case CEE_LDIND_I8:
13804                 return OP_LOADI8_MEMBASE;
13805         case CEE_LDIND_R4:
13806                 return OP_LOADR4_MEMBASE;
13807         case CEE_LDIND_R8:
13808                 return OP_LOADR8_MEMBASE;
13809         default:
13810                 g_assert_not_reached ();
13811         }
13812
13813         return -1;
13814 }
13815
13816 static int
13817 stind_to_store_membase (int opcode)
13818 {
13819         switch (opcode) {
13820         case CEE_STIND_I1:
13821                 return OP_STOREI1_MEMBASE_REG;
13822         case CEE_STIND_I2:
13823                 return OP_STOREI2_MEMBASE_REG;
13824         case CEE_STIND_I4:
13825                 return OP_STOREI4_MEMBASE_REG;
13826         case CEE_STIND_I:
13827         case CEE_STIND_REF:
13828                 return OP_STORE_MEMBASE_REG;
13829         case CEE_STIND_I8:
13830                 return OP_STOREI8_MEMBASE_REG;
13831         case CEE_STIND_R4:
13832                 return OP_STORER4_MEMBASE_REG;
13833         case CEE_STIND_R8:
13834                 return OP_STORER8_MEMBASE_REG;
13835         default:
13836                 g_assert_not_reached ();
13837         }
13838
13839         return -1;
13840 }
13841
13842 int
13843 mono_load_membase_to_load_mem (int opcode)
13844 {
13845         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
13846 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13847         switch (opcode) {
13848         case OP_LOAD_MEMBASE:
13849                 return OP_LOAD_MEM;
13850         case OP_LOADU1_MEMBASE:
13851                 return OP_LOADU1_MEM;
13852         case OP_LOADU2_MEMBASE:
13853                 return OP_LOADU2_MEM;
13854         case OP_LOADI4_MEMBASE:
13855                 return OP_LOADI4_MEM;
13856         case OP_LOADU4_MEMBASE:
13857                 return OP_LOADU4_MEM;
13858 #if SIZEOF_REGISTER == 8
13859         case OP_LOADI8_MEMBASE:
13860                 return OP_LOADI8_MEM;
13861 #endif
13862         }
13863 #endif
13864
13865         return -1;
13866 }
13867
13868 static inline int
13869 op_to_op_dest_membase (int store_opcode, int opcode)
13870 {
13871 #if defined(TARGET_X86)
13872         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
13873                 return -1;
13874
13875         switch (opcode) {
13876         case OP_IADD:
13877                 return OP_X86_ADD_MEMBASE_REG;
13878         case OP_ISUB:
13879                 return OP_X86_SUB_MEMBASE_REG;
13880         case OP_IAND:
13881                 return OP_X86_AND_MEMBASE_REG;
13882         case OP_IOR:
13883                 return OP_X86_OR_MEMBASE_REG;
13884         case OP_IXOR:
13885                 return OP_X86_XOR_MEMBASE_REG;
13886         case OP_ADD_IMM:
13887         case OP_IADD_IMM:
13888                 return OP_X86_ADD_MEMBASE_IMM;
13889         case OP_SUB_IMM:
13890         case OP_ISUB_IMM:
13891                 return OP_X86_SUB_MEMBASE_IMM;
13892         case OP_AND_IMM:
13893         case OP_IAND_IMM:
13894                 return OP_X86_AND_MEMBASE_IMM;
13895         case OP_OR_IMM:
13896         case OP_IOR_IMM:
13897                 return OP_X86_OR_MEMBASE_IMM;
13898         case OP_XOR_IMM:
13899         case OP_IXOR_IMM:
13900                 return OP_X86_XOR_MEMBASE_IMM;
13901         case OP_MOVE:
13902                 return OP_NOP;
13903         }
13904 #endif
13905
13906 #if defined(TARGET_AMD64)
13907         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
13908                 return -1;
13909
13910         switch (opcode) {
13911         case OP_IADD:
13912                 return OP_X86_ADD_MEMBASE_REG;
13913         case OP_ISUB:
13914                 return OP_X86_SUB_MEMBASE_REG;
13915         case OP_IAND:
13916                 return OP_X86_AND_MEMBASE_REG;
13917         case OP_IOR:
13918                 return OP_X86_OR_MEMBASE_REG;
13919         case OP_IXOR:
13920                 return OP_X86_XOR_MEMBASE_REG;
13921         case OP_IADD_IMM:
13922                 return OP_X86_ADD_MEMBASE_IMM;
13923         case OP_ISUB_IMM:
13924                 return OP_X86_SUB_MEMBASE_IMM;
13925         case OP_IAND_IMM:
13926                 return OP_X86_AND_MEMBASE_IMM;
13927         case OP_IOR_IMM:
13928                 return OP_X86_OR_MEMBASE_IMM;
13929         case OP_IXOR_IMM:
13930                 return OP_X86_XOR_MEMBASE_IMM;
13931         case OP_LADD:
13932                 return OP_AMD64_ADD_MEMBASE_REG;
13933         case OP_LSUB:
13934                 return OP_AMD64_SUB_MEMBASE_REG;
13935         case OP_LAND:
13936                 return OP_AMD64_AND_MEMBASE_REG;
13937         case OP_LOR:
13938                 return OP_AMD64_OR_MEMBASE_REG;
13939         case OP_LXOR:
13940                 return OP_AMD64_XOR_MEMBASE_REG;
13941         case OP_ADD_IMM:
13942         case OP_LADD_IMM:
13943                 return OP_AMD64_ADD_MEMBASE_IMM;
13944         case OP_SUB_IMM:
13945         case OP_LSUB_IMM:
13946                 return OP_AMD64_SUB_MEMBASE_IMM;
13947         case OP_AND_IMM:
13948         case OP_LAND_IMM:
13949                 return OP_AMD64_AND_MEMBASE_IMM;
13950         case OP_OR_IMM:
13951         case OP_LOR_IMM:
13952                 return OP_AMD64_OR_MEMBASE_IMM;
13953         case OP_XOR_IMM:
13954         case OP_LXOR_IMM:
13955                 return OP_AMD64_XOR_MEMBASE_IMM;
13956         case OP_MOVE:
13957                 return OP_NOP;
13958         }
13959 #endif
13960
13961         return -1;
13962 }
13963
13964 static inline int
13965 op_to_op_store_membase (int store_opcode, int opcode)
13966 {
13967 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13968         switch (opcode) {
13969         case OP_ICEQ:
13970                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13971                         return OP_X86_SETEQ_MEMBASE;
13972         case OP_CNE:
13973                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13974                         return OP_X86_SETNE_MEMBASE;
13975         }
13976 #endif
13977
13978         return -1;
13979 }
13980
13981 static inline int
13982 op_to_op_src1_membase (MonoCompile *cfg, int load_opcode, int opcode)
13983 {
13984 #ifdef TARGET_X86
13985         /* FIXME: This has sign extension issues */
13986         /*
13987         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13988                 return OP_X86_COMPARE_MEMBASE8_IMM;
13989         */
13990
13991         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13992                 return -1;
13993
13994         switch (opcode) {
13995         case OP_X86_PUSH:
13996                 return OP_X86_PUSH_MEMBASE;
13997         case OP_COMPARE_IMM:
13998         case OP_ICOMPARE_IMM:
13999                 return OP_X86_COMPARE_MEMBASE_IMM;
14000         case OP_COMPARE:
14001         case OP_ICOMPARE:
14002                 return OP_X86_COMPARE_MEMBASE_REG;
14003         }
14004 #endif
14005
14006 #ifdef TARGET_AMD64
14007         /* FIXME: This has sign extension issues */
14008         /*
14009         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
14010                 return OP_X86_COMPARE_MEMBASE8_IMM;
14011         */
14012
14013         switch (opcode) {
14014         case OP_X86_PUSH:
14015                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
14016                         return OP_X86_PUSH_MEMBASE;
14017                 break;
14018                 /* FIXME: This only works for 32 bit immediates
14019         case OP_COMPARE_IMM:
14020         case OP_LCOMPARE_IMM:
14021                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
14022                         return OP_AMD64_COMPARE_MEMBASE_IMM;
14023                 */
14024         case OP_ICOMPARE_IMM:
14025                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
14026                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
14027                 break;
14028         case OP_COMPARE:
14029         case OP_LCOMPARE:
14030                 if (cfg->backend->ilp32 && load_opcode == OP_LOAD_MEMBASE)
14031                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
14032                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
14033                         return OP_AMD64_COMPARE_MEMBASE_REG;
14034                 break;
14035         case OP_ICOMPARE:
14036                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
14037                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
14038                 break;
14039         }
14040 #endif
14041
14042         return -1;
14043 }
14044
14045 static inline int
14046 op_to_op_src2_membase (MonoCompile *cfg, int load_opcode, int opcode)
14047 {
14048 #ifdef TARGET_X86
14049         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
14050                 return -1;
14051         
14052         switch (opcode) {
14053         case OP_COMPARE:
14054         case OP_ICOMPARE:
14055                 return OP_X86_COMPARE_REG_MEMBASE;
14056         case OP_IADD:
14057                 return OP_X86_ADD_REG_MEMBASE;
14058         case OP_ISUB:
14059                 return OP_X86_SUB_REG_MEMBASE;
14060         case OP_IAND:
14061                 return OP_X86_AND_REG_MEMBASE;
14062         case OP_IOR:
14063                 return OP_X86_OR_REG_MEMBASE;
14064         case OP_IXOR:
14065                 return OP_X86_XOR_REG_MEMBASE;
14066         }
14067 #endif
14068
14069 #ifdef TARGET_AMD64
14070         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && cfg->backend->ilp32)) {
14071                 switch (opcode) {
14072                 case OP_ICOMPARE:
14073                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
14074                 case OP_IADD:
14075                         return OP_X86_ADD_REG_MEMBASE;
14076                 case OP_ISUB:
14077                         return OP_X86_SUB_REG_MEMBASE;
14078                 case OP_IAND:
14079                         return OP_X86_AND_REG_MEMBASE;
14080                 case OP_IOR:
14081                         return OP_X86_OR_REG_MEMBASE;
14082                 case OP_IXOR:
14083                         return OP_X86_XOR_REG_MEMBASE;
14084                 }
14085         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32)) {
14086                 switch (opcode) {
14087                 case OP_COMPARE:
14088                 case OP_LCOMPARE:
14089                         return OP_AMD64_COMPARE_REG_MEMBASE;
14090                 case OP_LADD:
14091                         return OP_AMD64_ADD_REG_MEMBASE;
14092                 case OP_LSUB:
14093                         return OP_AMD64_SUB_REG_MEMBASE;
14094                 case OP_LAND:
14095                         return OP_AMD64_AND_REG_MEMBASE;
14096                 case OP_LOR:
14097                         return OP_AMD64_OR_REG_MEMBASE;
14098                 case OP_LXOR:
14099                         return OP_AMD64_XOR_REG_MEMBASE;
14100                 }
14101         }
14102 #endif
14103
14104         return -1;
14105 }
14106
14107 int
14108 mono_op_to_op_imm_noemul (int opcode)
14109 {
14110         switch (opcode) {
14111 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
14112         case OP_LSHR:
14113         case OP_LSHL:
14114         case OP_LSHR_UN:
14115                 return -1;
14116 #endif
14117 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
14118         case OP_IDIV:
14119         case OP_IDIV_UN:
14120         case OP_IREM:
14121         case OP_IREM_UN:
14122                 return -1;
14123 #endif
14124 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
14125         case OP_IMUL:
14126                 return -1;
14127 #endif
14128         default:
14129                 return mono_op_to_op_imm (opcode);
14130         }
14131 }
14132
14133 /**
14134  * mono_handle_global_vregs:
14135  *
14136  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
14137  * for them.
14138  */
14139 void
14140 mono_handle_global_vregs (MonoCompile *cfg)
14141 {
14142         gint32 *vreg_to_bb;
14143         MonoBasicBlock *bb;
14144         int i, pos;
14145
14146         vreg_to_bb = (gint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
14147
14148 #ifdef MONO_ARCH_SIMD_INTRINSICS
14149         if (cfg->uses_simd_intrinsics)
14150                 mono_simd_simplify_indirection (cfg);
14151 #endif
14152
14153         /* Find local vregs used in more than one bb */
14154         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
14155                 MonoInst *ins = bb->code;       
14156                 int block_num = bb->block_num;
14157
14158                 if (cfg->verbose_level > 2)
14159                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
14160
14161                 cfg->cbb = bb;
14162                 for (; ins; ins = ins->next) {
14163                         const char *spec = INS_INFO (ins->opcode);
14164                         int regtype = 0, regindex;
14165                         gint32 prev_bb;
14166
14167                         if (G_UNLIKELY (cfg->verbose_level > 2))
14168                                 mono_print_ins (ins);
14169
14170                         g_assert (ins->opcode >= MONO_CEE_LAST);
14171
14172                         for (regindex = 0; regindex < 4; regindex ++) {
14173                                 int vreg = 0;
14174
14175                                 if (regindex == 0) {
14176                                         regtype = spec [MONO_INST_DEST];
14177                                         if (regtype == ' ')
14178                                                 continue;
14179                                         vreg = ins->dreg;
14180                                 } else if (regindex == 1) {
14181                                         regtype = spec [MONO_INST_SRC1];
14182                                         if (regtype == ' ')
14183                                                 continue;
14184                                         vreg = ins->sreg1;
14185                                 } else if (regindex == 2) {
14186                                         regtype = spec [MONO_INST_SRC2];
14187                                         if (regtype == ' ')
14188                                                 continue;
14189                                         vreg = ins->sreg2;
14190                                 } else if (regindex == 3) {
14191                                         regtype = spec [MONO_INST_SRC3];
14192                                         if (regtype == ' ')
14193                                                 continue;
14194                                         vreg = ins->sreg3;
14195                                 }
14196
14197 #if SIZEOF_REGISTER == 4
14198                                 /* In the LLVM case, the long opcodes are not decomposed */
14199                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
14200                                         /*
14201                                          * Since some instructions reference the original long vreg,
14202                                          * and some reference the two component vregs, it is quite hard
14203                                          * to determine when it needs to be global. So be conservative.
14204                                          */
14205                                         if (!get_vreg_to_inst (cfg, vreg)) {
14206                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
14207
14208                                                 if (cfg->verbose_level > 2)
14209                                                         printf ("LONG VREG R%d made global.\n", vreg);
14210                                         }
14211
14212                                         /*
14213                                          * Make the component vregs volatile since the optimizations can
14214                                          * get confused otherwise.
14215                                          */
14216                                         get_vreg_to_inst (cfg, MONO_LVREG_LS (vreg))->flags |= MONO_INST_VOLATILE;
14217                                         get_vreg_to_inst (cfg, MONO_LVREG_MS (vreg))->flags |= MONO_INST_VOLATILE;
14218                                 }
14219 #endif
14220
14221                                 g_assert (vreg != -1);
14222
14223                                 prev_bb = vreg_to_bb [vreg];
14224                                 if (prev_bb == 0) {
14225                                         /* 0 is a valid block num */
14226                                         vreg_to_bb [vreg] = block_num + 1;
14227                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
14228                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
14229                                                 continue;
14230
14231                                         if (!get_vreg_to_inst (cfg, vreg)) {
14232                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14233                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
14234
14235                                                 switch (regtype) {
14236                                                 case 'i':
14237                                                         if (vreg_is_ref (cfg, vreg))
14238                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
14239                                                         else
14240                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
14241                                                         break;
14242                                                 case 'l':
14243                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
14244                                                         break;
14245                                                 case 'f':
14246                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
14247                                                         break;
14248                                                 case 'v':
14249                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
14250                                                         break;
14251                                                 default:
14252                                                         g_assert_not_reached ();
14253                                                 }
14254                                         }
14255
14256                                         /* Flag as having been used in more than one bb */
14257                                         vreg_to_bb [vreg] = -1;
14258                                 }
14259                         }
14260                 }
14261         }
14262
14263         /* If a variable is used in only one bblock, convert it into a local vreg */
14264         for (i = 0; i < cfg->num_varinfo; i++) {
14265                 MonoInst *var = cfg->varinfo [i];
14266                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
14267
14268                 switch (var->type) {
14269                 case STACK_I4:
14270                 case STACK_OBJ:
14271                 case STACK_PTR:
14272                 case STACK_MP:
14273                 case STACK_VTYPE:
14274 #if SIZEOF_REGISTER == 8
14275                 case STACK_I8:
14276 #endif
14277 #if !defined(TARGET_X86)
14278                 /* Enabling this screws up the fp stack on x86 */
14279                 case STACK_R8:
14280 #endif
14281                         if (mono_arch_is_soft_float ())
14282                                 break;
14283
14284                         /*
14285                         if (var->type == STACK_VTYPE && cfg->gsharedvt && mini_is_gsharedvt_variable_type (var->inst_vtype))
14286                                 break;
14287                         */
14288
14289                         /* Arguments are implicitly global */
14290                         /* Putting R4 vars into registers doesn't work currently */
14291                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
14292                         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) {
14293                                 /* 
14294                                  * Make that the variable's liveness interval doesn't contain a call, since
14295                                  * that would cause the lvreg to be spilled, making the whole optimization
14296                                  * useless.
14297                                  */
14298                                 /* This is too slow for JIT compilation */
14299 #if 0
14300                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
14301                                         MonoInst *ins;
14302                                         int def_index, call_index, ins_index;
14303                                         gboolean spilled = FALSE;
14304
14305                                         def_index = -1;
14306                                         call_index = -1;
14307                                         ins_index = 0;
14308                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
14309                                                 const char *spec = INS_INFO (ins->opcode);
14310
14311                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
14312                                                         def_index = ins_index;
14313
14314                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
14315                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
14316                                                         if (call_index > def_index) {
14317                                                                 spilled = TRUE;
14318                                                                 break;
14319                                                         }
14320                                                 }
14321
14322                                                 if (MONO_IS_CALL (ins))
14323                                                         call_index = ins_index;
14324
14325                                                 ins_index ++;
14326                                         }
14327
14328                                         if (spilled)
14329                                                 break;
14330                                 }
14331 #endif
14332
14333                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14334                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
14335                                 var->flags |= MONO_INST_IS_DEAD;
14336                                 cfg->vreg_to_inst [var->dreg] = NULL;
14337                         }
14338                         break;
14339                 }
14340         }
14341
14342         /* 
14343          * Compress the varinfo and vars tables so the liveness computation is faster and
14344          * takes up less space.
14345          */
14346         pos = 0;
14347         for (i = 0; i < cfg->num_varinfo; ++i) {
14348                 MonoInst *var = cfg->varinfo [i];
14349                 if (pos < i && cfg->locals_start == i)
14350                         cfg->locals_start = pos;
14351                 if (!(var->flags & MONO_INST_IS_DEAD)) {
14352                         if (pos < i) {
14353                                 cfg->varinfo [pos] = cfg->varinfo [i];
14354                                 cfg->varinfo [pos]->inst_c0 = pos;
14355                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
14356                                 cfg->vars [pos].idx = pos;
14357 #if SIZEOF_REGISTER == 4
14358                                 if (cfg->varinfo [pos]->type == STACK_I8) {
14359                                         /* Modify the two component vars too */
14360                                         MonoInst *var1;
14361
14362                                         var1 = get_vreg_to_inst (cfg, MONO_LVREG_LS (cfg->varinfo [pos]->dreg));
14363                                         var1->inst_c0 = pos;
14364                                         var1 = get_vreg_to_inst (cfg, MONO_LVREG_MS (cfg->varinfo [pos]->dreg));
14365                                         var1->inst_c0 = pos;
14366                                 }
14367 #endif
14368                         }
14369                         pos ++;
14370                 }
14371         }
14372         cfg->num_varinfo = pos;
14373         if (cfg->locals_start > cfg->num_varinfo)
14374                 cfg->locals_start = cfg->num_varinfo;
14375 }
14376
14377 /*
14378  * mono_allocate_gsharedvt_vars:
14379  *
14380  *   Allocate variables with gsharedvt types to entries in the MonoGSharedVtMethodRuntimeInfo.entries array.
14381  * Initialize cfg->gsharedvt_vreg_to_idx with the mapping between vregs and indexes.
14382  */
14383 void
14384 mono_allocate_gsharedvt_vars (MonoCompile *cfg)
14385 {
14386         int i;
14387
14388         cfg->gsharedvt_vreg_to_idx = (int *)mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
14389
14390         for (i = 0; i < cfg->num_varinfo; ++i) {
14391                 MonoInst *ins = cfg->varinfo [i];
14392                 int idx;
14393
14394                 if (mini_is_gsharedvt_variable_type (ins->inst_vtype)) {
14395                         if (i >= cfg->locals_start) {
14396                                 /* Local */
14397                                 idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
14398                                 cfg->gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
14399                                 ins->opcode = OP_GSHAREDVT_LOCAL;
14400                                 ins->inst_imm = idx;
14401                         } else {
14402                                 /* Arg */
14403                                 cfg->gsharedvt_vreg_to_idx [ins->dreg] = -1;
14404                                 ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
14405                         }
14406                 }
14407         }
14408 }
14409
14410 /**
14411  * mono_spill_global_vars:
14412  *
14413  *   Generate spill code for variables which are not allocated to registers, 
14414  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
14415  * code is generated which could be optimized by the local optimization passes.
14416  */
14417 void
14418 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
14419 {
14420         MonoBasicBlock *bb;
14421         char spec2 [16];
14422         int orig_next_vreg;
14423         guint32 *vreg_to_lvreg;
14424         guint32 *lvregs;
14425         guint32 i, lvregs_len;
14426         gboolean dest_has_lvreg = FALSE;
14427         MonoStackType stacktypes [128];
14428         MonoInst **live_range_start, **live_range_end;
14429         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
14430
14431         *need_local_opts = FALSE;
14432
14433         memset (spec2, 0, sizeof (spec2));
14434
14435         /* FIXME: Move this function to mini.c */
14436         stacktypes ['i'] = STACK_PTR;
14437         stacktypes ['l'] = STACK_I8;
14438         stacktypes ['f'] = STACK_R8;
14439 #ifdef MONO_ARCH_SIMD_INTRINSICS
14440         stacktypes ['x'] = STACK_VTYPE;
14441 #endif
14442
14443 #if SIZEOF_REGISTER == 4
14444         /* Create MonoInsts for longs */
14445         for (i = 0; i < cfg->num_varinfo; i++) {
14446                 MonoInst *ins = cfg->varinfo [i];
14447
14448                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
14449                         switch (ins->type) {
14450                         case STACK_R8:
14451                         case STACK_I8: {
14452                                 MonoInst *tree;
14453
14454                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
14455                                         break;
14456
14457                                 g_assert (ins->opcode == OP_REGOFFSET);
14458
14459                                 tree = get_vreg_to_inst (cfg, MONO_LVREG_LS (ins->dreg));
14460                                 g_assert (tree);
14461                                 tree->opcode = OP_REGOFFSET;
14462                                 tree->inst_basereg = ins->inst_basereg;
14463                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
14464
14465                                 tree = get_vreg_to_inst (cfg, MONO_LVREG_MS (ins->dreg));
14466                                 g_assert (tree);
14467                                 tree->opcode = OP_REGOFFSET;
14468                                 tree->inst_basereg = ins->inst_basereg;
14469                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
14470                                 break;
14471                         }
14472                         default:
14473                                 break;
14474                         }
14475                 }
14476         }
14477 #endif
14478
14479         if (cfg->compute_gc_maps) {
14480                 /* registers need liveness info even for !non refs */
14481                 for (i = 0; i < cfg->num_varinfo; i++) {
14482                         MonoInst *ins = cfg->varinfo [i];
14483
14484                         if (ins->opcode == OP_REGVAR)
14485                                 ins->flags |= MONO_INST_GC_TRACK;
14486                 }
14487         }
14488                 
14489         /* FIXME: widening and truncation */
14490
14491         /*
14492          * As an optimization, when a variable allocated to the stack is first loaded into 
14493          * an lvreg, we will remember the lvreg and use it the next time instead of loading
14494          * the variable again.
14495          */
14496         orig_next_vreg = cfg->next_vreg;
14497         vreg_to_lvreg = (guint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
14498         lvregs = (guint32 *)mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
14499         lvregs_len = 0;
14500
14501         /* 
14502          * These arrays contain the first and last instructions accessing a given
14503          * variable.
14504          * Since we emit bblocks in the same order we process them here, and we
14505          * don't split live ranges, these will precisely describe the live range of
14506          * the variable, i.e. the instruction range where a valid value can be found
14507          * in the variables location.
14508          * The live range is computed using the liveness info computed by the liveness pass.
14509          * We can't use vmv->range, since that is an abstract live range, and we need
14510          * one which is instruction precise.
14511          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
14512          */
14513         /* FIXME: Only do this if debugging info is requested */
14514         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
14515         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
14516         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
14517         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
14518         
14519         /* Add spill loads/stores */
14520         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
14521                 MonoInst *ins;
14522
14523                 if (cfg->verbose_level > 2)
14524                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
14525
14526                 /* Clear vreg_to_lvreg array */
14527                 for (i = 0; i < lvregs_len; i++)
14528                         vreg_to_lvreg [lvregs [i]] = 0;
14529                 lvregs_len = 0;
14530
14531                 cfg->cbb = bb;
14532                 MONO_BB_FOR_EACH_INS (bb, ins) {
14533                         const char *spec = INS_INFO (ins->opcode);
14534                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
14535                         gboolean store, no_lvreg;
14536                         int sregs [MONO_MAX_SRC_REGS];
14537
14538                         if (G_UNLIKELY (cfg->verbose_level > 2))
14539                                 mono_print_ins (ins);
14540
14541                         if (ins->opcode == OP_NOP)
14542                                 continue;
14543
14544                         /* 
14545                          * We handle LDADDR here as well, since it can only be decomposed
14546                          * when variable addresses are known.
14547                          */
14548                         if (ins->opcode == OP_LDADDR) {
14549                                 MonoInst *var = (MonoInst *)ins->inst_p0;
14550
14551                                 if (var->opcode == OP_VTARG_ADDR) {
14552                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
14553                                         MonoInst *vtaddr = var->inst_left;
14554                                         if (vtaddr->opcode == OP_REGVAR) {
14555                                                 ins->opcode = OP_MOVE;
14556                                                 ins->sreg1 = vtaddr->dreg;
14557                                         }
14558                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
14559                                                 ins->opcode = OP_LOAD_MEMBASE;
14560                                                 ins->inst_basereg = vtaddr->inst_basereg;
14561                                                 ins->inst_offset = vtaddr->inst_offset;
14562                                         } else
14563                                                 NOT_IMPLEMENTED;
14564                                 } else if (cfg->gsharedvt && cfg->gsharedvt_vreg_to_idx [var->dreg] < 0) {
14565                                         /* gsharedvt arg passed by ref */
14566                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
14567
14568                                         ins->opcode = OP_LOAD_MEMBASE;
14569                                         ins->inst_basereg = var->inst_basereg;
14570                                         ins->inst_offset = var->inst_offset;
14571                                 } else if (cfg->gsharedvt && cfg->gsharedvt_vreg_to_idx [var->dreg]) {
14572                                         MonoInst *load, *load2, *load3;
14573                                         int idx = cfg->gsharedvt_vreg_to_idx [var->dreg] - 1;
14574                                         int reg1, reg2, reg3;
14575                                         MonoInst *info_var = cfg->gsharedvt_info_var;
14576                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
14577
14578                                         /*
14579                                          * gsharedvt local.
14580                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
14581                                          */
14582
14583                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
14584
14585                                         g_assert (info_var);
14586                                         g_assert (locals_var);
14587
14588                                         /* Mark the instruction used to compute the locals var as used */
14589                                         cfg->gsharedvt_locals_var_ins = NULL;
14590
14591                                         /* Load the offset */
14592                                         if (info_var->opcode == OP_REGOFFSET) {
14593                                                 reg1 = alloc_ireg (cfg);
14594                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
14595                                         } else if (info_var->opcode == OP_REGVAR) {
14596                                                 load = NULL;
14597                                                 reg1 = info_var->dreg;
14598                                         } else {
14599                                                 g_assert_not_reached ();
14600                                         }
14601                                         reg2 = alloc_ireg (cfg);
14602                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
14603                                         /* Load the locals area address */
14604                                         reg3 = alloc_ireg (cfg);
14605                                         if (locals_var->opcode == OP_REGOFFSET) {
14606                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
14607                                         } else if (locals_var->opcode == OP_REGVAR) {
14608                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
14609                                         } else {
14610                                                 g_assert_not_reached ();
14611                                         }
14612                                         /* Compute the address */
14613                                         ins->opcode = OP_PADD;
14614                                         ins->sreg1 = reg3;
14615                                         ins->sreg2 = reg2;
14616
14617                                         mono_bblock_insert_before_ins (bb, ins, load3);
14618                                         mono_bblock_insert_before_ins (bb, load3, load2);
14619                                         if (load)
14620                                                 mono_bblock_insert_before_ins (bb, load2, load);
14621                                 } else {
14622                                         g_assert (var->opcode == OP_REGOFFSET);
14623
14624                                         ins->opcode = OP_ADD_IMM;
14625                                         ins->sreg1 = var->inst_basereg;
14626                                         ins->inst_imm = var->inst_offset;
14627                                 }
14628
14629                                 *need_local_opts = TRUE;
14630                                 spec = INS_INFO (ins->opcode);
14631                         }
14632
14633                         if (ins->opcode < MONO_CEE_LAST) {
14634                                 mono_print_ins (ins);
14635                                 g_assert_not_reached ();
14636                         }
14637
14638                         /*
14639                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
14640                          * src register.
14641                          * FIXME:
14642                          */
14643                         if (MONO_IS_STORE_MEMBASE (ins)) {
14644                                 tmp_reg = ins->dreg;
14645                                 ins->dreg = ins->sreg2;
14646                                 ins->sreg2 = tmp_reg;
14647                                 store = TRUE;
14648
14649                                 spec2 [MONO_INST_DEST] = ' ';
14650                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14651                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14652                                 spec2 [MONO_INST_SRC3] = ' ';
14653                                 spec = spec2;
14654                         } else if (MONO_IS_STORE_MEMINDEX (ins))
14655                                 g_assert_not_reached ();
14656                         else
14657                                 store = FALSE;
14658                         no_lvreg = FALSE;
14659
14660                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
14661                                 printf ("\t %.3s %d", spec, ins->dreg);
14662                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
14663                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
14664                                         printf (" %d", sregs [srcindex]);
14665                                 printf ("\n");
14666                         }
14667
14668                         /***************/
14669                         /*    DREG     */
14670                         /***************/
14671                         regtype = spec [MONO_INST_DEST];
14672                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
14673                         prev_dreg = -1;
14674
14675                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
14676                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
14677                                 MonoInst *store_ins;
14678                                 int store_opcode;
14679                                 MonoInst *def_ins = ins;
14680                                 int dreg = ins->dreg; /* The original vreg */
14681
14682                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
14683
14684                                 if (var->opcode == OP_REGVAR) {
14685                                         ins->dreg = var->dreg;
14686                                 } 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)) {
14687                                         /* 
14688                                          * Instead of emitting a load+store, use a _membase opcode.
14689                                          */
14690                                         g_assert (var->opcode == OP_REGOFFSET);
14691                                         if (ins->opcode == OP_MOVE) {
14692                                                 NULLIFY_INS (ins);
14693                                                 def_ins = NULL;
14694                                         } else {
14695                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
14696                                                 ins->inst_basereg = var->inst_basereg;
14697                                                 ins->inst_offset = var->inst_offset;
14698                                                 ins->dreg = -1;
14699                                         }
14700                                         spec = INS_INFO (ins->opcode);
14701                                 } else {
14702                                         guint32 lvreg;
14703
14704                                         g_assert (var->opcode == OP_REGOFFSET);
14705
14706                                         prev_dreg = ins->dreg;
14707
14708                                         /* Invalidate any previous lvreg for this vreg */
14709                                         vreg_to_lvreg [ins->dreg] = 0;
14710
14711                                         lvreg = 0;
14712
14713                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
14714                                                 regtype = 'l';
14715                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
14716                                         }
14717
14718                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
14719
14720 #if SIZEOF_REGISTER != 8
14721                                         if (regtype == 'l') {
14722                                                 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));
14723                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14724                                                 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));
14725                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14726                                                 def_ins = store_ins;
14727                                         }
14728                                         else
14729 #endif
14730                                         {
14731                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
14732
14733                                                 /* Try to fuse the store into the instruction itself */
14734                                                 /* FIXME: Add more instructions */
14735                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
14736                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
14737                                                         ins->inst_imm = ins->inst_c0;
14738                                                         ins->inst_destbasereg = var->inst_basereg;
14739                                                         ins->inst_offset = var->inst_offset;
14740                                                         spec = INS_INFO (ins->opcode);
14741                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE) || (ins->opcode == OP_RMOVE))) {
14742                                                         ins->opcode = store_opcode;
14743                                                         ins->inst_destbasereg = var->inst_basereg;
14744                                                         ins->inst_offset = var->inst_offset;
14745
14746                                                         no_lvreg = TRUE;
14747
14748                                                         tmp_reg = ins->dreg;
14749                                                         ins->dreg = ins->sreg2;
14750                                                         ins->sreg2 = tmp_reg;
14751                                                         store = TRUE;
14752
14753                                                         spec2 [MONO_INST_DEST] = ' ';
14754                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14755                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14756                                                         spec2 [MONO_INST_SRC3] = ' ';
14757                                                         spec = spec2;
14758                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
14759                                                         // FIXME: The backends expect the base reg to be in inst_basereg
14760                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
14761                                                         ins->dreg = -1;
14762                                                         ins->inst_basereg = var->inst_basereg;
14763                                                         ins->inst_offset = var->inst_offset;
14764                                                         spec = INS_INFO (ins->opcode);
14765                                                 } else {
14766                                                         /* printf ("INS: "); mono_print_ins (ins); */
14767                                                         /* Create a store instruction */
14768                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
14769
14770                                                         /* Insert it after the instruction */
14771                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
14772
14773                                                         def_ins = store_ins;
14774
14775                                                         /* 
14776                                                          * We can't assign ins->dreg to var->dreg here, since the
14777                                                          * sregs could use it. So set a flag, and do it after
14778                                                          * the sregs.
14779                                                          */
14780                                                         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)))
14781                                                                 dest_has_lvreg = TRUE;
14782                                                 }
14783                                         }
14784                                 }
14785
14786                                 if (def_ins && !live_range_start [dreg]) {
14787                                         live_range_start [dreg] = def_ins;
14788                                         live_range_start_bb [dreg] = bb;
14789                                 }
14790
14791                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
14792                                         MonoInst *tmp;
14793
14794                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
14795                                         tmp->inst_c1 = dreg;
14796                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
14797                                 }
14798                         }
14799
14800                         /************/
14801                         /*  SREGS   */
14802                         /************/
14803                         num_sregs = mono_inst_get_src_registers (ins, sregs);
14804                         for (srcindex = 0; srcindex < 3; ++srcindex) {
14805                                 regtype = spec [MONO_INST_SRC1 + srcindex];
14806                                 sreg = sregs [srcindex];
14807
14808                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
14809                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
14810                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
14811                                         MonoInst *use_ins = ins;
14812                                         MonoInst *load_ins;
14813                                         guint32 load_opcode;
14814
14815                                         if (var->opcode == OP_REGVAR) {
14816                                                 sregs [srcindex] = var->dreg;
14817                                                 //mono_inst_set_src_registers (ins, sregs);
14818                                                 live_range_end [sreg] = use_ins;
14819                                                 live_range_end_bb [sreg] = bb;
14820
14821                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14822                                                         MonoInst *tmp;
14823
14824                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14825                                                         /* var->dreg is a hreg */
14826                                                         tmp->inst_c1 = sreg;
14827                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
14828                                                 }
14829
14830                                                 continue;
14831                                         }
14832
14833                                         g_assert (var->opcode == OP_REGOFFSET);
14834                                                 
14835                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
14836
14837                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
14838
14839                                         if (vreg_to_lvreg [sreg]) {
14840                                                 g_assert (vreg_to_lvreg [sreg] != -1);
14841
14842                                                 /* The variable is already loaded to an lvreg */
14843                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14844                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
14845                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
14846                                                 //mono_inst_set_src_registers (ins, sregs);
14847                                                 continue;
14848                                         }
14849
14850                                         /* Try to fuse the load into the instruction */
14851                                         if ((srcindex == 0) && (op_to_op_src1_membase (cfg, load_opcode, ins->opcode) != -1)) {
14852                                                 ins->opcode = op_to_op_src1_membase (cfg, load_opcode, ins->opcode);
14853                                                 sregs [0] = var->inst_basereg;
14854                                                 //mono_inst_set_src_registers (ins, sregs);
14855                                                 ins->inst_offset = var->inst_offset;
14856                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (cfg, load_opcode, ins->opcode) != -1)) {
14857                                                 ins->opcode = op_to_op_src2_membase (cfg, load_opcode, ins->opcode);
14858                                                 sregs [1] = var->inst_basereg;
14859                                                 //mono_inst_set_src_registers (ins, sregs);
14860                                                 ins->inst_offset = var->inst_offset;
14861                                         } else {
14862                                                 if (MONO_IS_REAL_MOVE (ins)) {
14863                                                         ins->opcode = OP_NOP;
14864                                                         sreg = ins->dreg;
14865                                                 } else {
14866                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
14867
14868                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
14869
14870                                                         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) {
14871                                                                 if (var->dreg == prev_dreg) {
14872                                                                         /*
14873                                                                          * sreg refers to the value loaded by the load
14874                                                                          * emitted below, but we need to use ins->dreg
14875                                                                          * since it refers to the store emitted earlier.
14876                                                                          */
14877                                                                         sreg = ins->dreg;
14878                                                                 }
14879                                                                 g_assert (sreg != -1);
14880                                                                 vreg_to_lvreg [var->dreg] = sreg;
14881                                                                 g_assert (lvregs_len < 1024);
14882                                                                 lvregs [lvregs_len ++] = var->dreg;
14883                                                         }
14884                                                 }
14885
14886                                                 sregs [srcindex] = sreg;
14887                                                 //mono_inst_set_src_registers (ins, sregs);
14888
14889 #if SIZEOF_REGISTER != 8
14890                                                 if (regtype == 'l') {
14891                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_MS (sreg), var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
14892                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14893                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_LS (sreg), var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
14894                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14895                                                         use_ins = load_ins;
14896                                                 }
14897                                                 else
14898 #endif
14899                                                 {
14900 #if SIZEOF_REGISTER == 4
14901                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
14902 #endif
14903                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
14904                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14905                                                         use_ins = load_ins;
14906                                                 }
14907                                         }
14908
14909                                         if (var->dreg < orig_next_vreg) {
14910                                                 live_range_end [var->dreg] = use_ins;
14911                                                 live_range_end_bb [var->dreg] = bb;
14912                                         }
14913
14914                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14915                                                 MonoInst *tmp;
14916
14917                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14918                                                 tmp->inst_c1 = var->dreg;
14919                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
14920                                         }
14921                                 }
14922                         }
14923                         mono_inst_set_src_registers (ins, sregs);
14924
14925                         if (dest_has_lvreg) {
14926                                 g_assert (ins->dreg != -1);
14927                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
14928                                 g_assert (lvregs_len < 1024);
14929                                 lvregs [lvregs_len ++] = prev_dreg;
14930                                 dest_has_lvreg = FALSE;
14931                         }
14932
14933                         if (store) {
14934                                 tmp_reg = ins->dreg;
14935                                 ins->dreg = ins->sreg2;
14936                                 ins->sreg2 = tmp_reg;
14937                         }
14938
14939                         if (MONO_IS_CALL (ins)) {
14940                                 /* Clear vreg_to_lvreg array */
14941                                 for (i = 0; i < lvregs_len; i++)
14942                                         vreg_to_lvreg [lvregs [i]] = 0;
14943                                 lvregs_len = 0;
14944                         } else if (ins->opcode == OP_NOP) {
14945                                 ins->dreg = -1;
14946                                 MONO_INST_NULLIFY_SREGS (ins);
14947                         }
14948
14949                         if (cfg->verbose_level > 2)
14950                                 mono_print_ins_index (1, ins);
14951                 }
14952
14953                 /* Extend the live range based on the liveness info */
14954                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
14955                         for (i = 0; i < cfg->num_varinfo; i ++) {
14956                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
14957
14958                                 if (vreg_is_volatile (cfg, vi->vreg))
14959                                         /* The liveness info is incomplete */
14960                                         continue;
14961
14962                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
14963                                         /* Live from at least the first ins of this bb */
14964                                         live_range_start [vi->vreg] = bb->code;
14965                                         live_range_start_bb [vi->vreg] = bb;
14966                                 }
14967
14968                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
14969                                         /* Live at least until the last ins of this bb */
14970                                         live_range_end [vi->vreg] = bb->last_ins;
14971                                         live_range_end_bb [vi->vreg] = bb;
14972                                 }
14973                         }
14974                 }
14975         }
14976         
14977         /*
14978          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
14979          * by storing the current native offset into MonoMethodVar->live_range_start/end.
14980          */
14981         if (cfg->backend->have_liverange_ops && cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
14982                 for (i = 0; i < cfg->num_varinfo; ++i) {
14983                         int vreg = MONO_VARINFO (cfg, i)->vreg;
14984                         MonoInst *ins;
14985
14986                         if (live_range_start [vreg]) {
14987                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
14988                                 ins->inst_c0 = i;
14989                                 ins->inst_c1 = vreg;
14990                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
14991                         }
14992                         if (live_range_end [vreg]) {
14993                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
14994                                 ins->inst_c0 = i;
14995                                 ins->inst_c1 = vreg;
14996                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
14997                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
14998                                 else
14999                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
15000                         }
15001                 }
15002         }
15003
15004         if (cfg->gsharedvt_locals_var_ins) {
15005                 /* Nullify if unused */
15006                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
15007                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
15008         }
15009
15010         g_free (live_range_start);
15011         g_free (live_range_end);
15012         g_free (live_range_start_bb);
15013         g_free (live_range_end_bb);
15014 }
15015
15016 /**
15017  * FIXME:
15018  * - use 'iadd' instead of 'int_add'
15019  * - handling ovf opcodes: decompose in method_to_ir.
15020  * - unify iregs/fregs
15021  *   -> partly done, the missing parts are:
15022  *   - a more complete unification would involve unifying the hregs as well, so
15023  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
15024  *     would no longer map to the machine hregs, so the code generators would need to
15025  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
15026  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
15027  *     fp/non-fp branches speeds it up by about 15%.
15028  * - use sext/zext opcodes instead of shifts
15029  * - add OP_ICALL
15030  * - get rid of TEMPLOADs if possible and use vregs instead
15031  * - clean up usage of OP_P/OP_ opcodes
15032  * - cleanup usage of DUMMY_USE
15033  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
15034  *   stack
15035  * - set the stack type and allocate a dreg in the EMIT_NEW macros
15036  * - get rid of all the <foo>2 stuff when the new JIT is ready.
15037  * - make sure handle_stack_args () is called before the branch is emitted
15038  * - when the new IR is done, get rid of all unused stuff
15039  * - COMPARE/BEQ as separate instructions or unify them ?
15040  *   - keeping them separate allows specialized compare instructions like
15041  *     compare_imm, compare_membase
15042  *   - most back ends unify fp compare+branch, fp compare+ceq
15043  * - integrate mono_save_args into inline_method
15044  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
15045  * - handle long shift opts on 32 bit platforms somehow: they require 
15046  *   3 sregs (2 for arg1 and 1 for arg2)
15047  * - make byref a 'normal' type.
15048  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
15049  *   variable if needed.
15050  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
15051  *   like inline_method.
15052  * - remove inlining restrictions
15053  * - fix LNEG and enable cfold of INEG
15054  * - generalize x86 optimizations like ldelema as a peephole optimization
15055  * - add store_mem_imm for amd64
15056  * - optimize the loading of the interruption flag in the managed->native wrappers
15057  * - avoid special handling of OP_NOP in passes
15058  * - move code inserting instructions into one function/macro.
15059  * - try a coalescing phase after liveness analysis
15060  * - add float -> vreg conversion + local optimizations on !x86
15061  * - figure out how to handle decomposed branches during optimizations, ie.
15062  *   compare+branch, op_jump_table+op_br etc.
15063  * - promote RuntimeXHandles to vregs
15064  * - vtype cleanups:
15065  *   - add a NEW_VARLOADA_VREG macro
15066  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
15067  *   accessing vtype fields.
15068  * - get rid of I8CONST on 64 bit platforms
15069  * - dealing with the increase in code size due to branches created during opcode
15070  *   decomposition:
15071  *   - use extended basic blocks
15072  *     - all parts of the JIT
15073  *     - handle_global_vregs () && local regalloc
15074  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
15075  * - sources of increase in code size:
15076  *   - vtypes
15077  *   - long compares
15078  *   - isinst and castclass
15079  *   - lvregs not allocated to global registers even if used multiple times
15080  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
15081  *   meaningful.
15082  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
15083  * - add all micro optimizations from the old JIT
15084  * - put tree optimizations into the deadce pass
15085  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
15086  *   specific function.
15087  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
15088  *   fcompare + branchCC.
15089  * - create a helper function for allocating a stack slot, taking into account 
15090  *   MONO_CFG_HAS_SPILLUP.
15091  * - merge r68207.
15092  * - merge the ia64 switch changes.
15093  * - optimize mono_regstate2_alloc_int/float.
15094  * - fix the pessimistic handling of variables accessed in exception handler blocks.
15095  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
15096  *   parts of the tree could be separated by other instructions, killing the tree
15097  *   arguments, or stores killing loads etc. Also, should we fold loads into other
15098  *   instructions if the result of the load is used multiple times ?
15099  * - make the REM_IMM optimization in mini-x86.c arch-independent.
15100  * - LAST MERGE: 108395.
15101  * - when returning vtypes in registers, generate IR and append it to the end of the
15102  *   last bb instead of doing it in the epilog.
15103  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
15104  */
15105
15106 /*
15107
15108 NOTES
15109 -----
15110
15111 - When to decompose opcodes:
15112   - earlier: this makes some optimizations hard to implement, since the low level IR
15113   no longer contains the neccessary information. But it is easier to do.
15114   - later: harder to implement, enables more optimizations.
15115 - Branches inside bblocks:
15116   - created when decomposing complex opcodes. 
15117     - branches to another bblock: harmless, but not tracked by the branch 
15118       optimizations, so need to branch to a label at the start of the bblock.
15119     - branches to inside the same bblock: very problematic, trips up the local
15120       reg allocator. Can be fixed by spitting the current bblock, but that is a
15121       complex operation, since some local vregs can become global vregs etc.
15122 - Local/global vregs:
15123   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
15124     local register allocator.
15125   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
15126     structure, created by mono_create_var (). Assigned to hregs or the stack by
15127     the global register allocator.
15128 - When to do optimizations like alu->alu_imm:
15129   - earlier -> saves work later on since the IR will be smaller/simpler
15130   - later -> can work on more instructions
15131 - Handling of valuetypes:
15132   - When a vtype is pushed on the stack, a new temporary is created, an 
15133     instruction computing its address (LDADDR) is emitted and pushed on
15134     the stack. Need to optimize cases when the vtype is used immediately as in
15135     argument passing, stloc etc.
15136 - Instead of the to_end stuff in the old JIT, simply call the function handling
15137   the values on the stack before emitting the last instruction of the bb.
15138 */
15139
15140 #endif /* DISABLE_JIT */