[delegate-virtual-trampoline] Add virtual functions delegate trampoline support
[mono.git] / mono / mini / mini-arm.c
1 /*
2  * mini-arm.c: ARM backend for the Mono code generator
3  *
4  * Authors:
5  *   Paolo Molaro (lupus@ximian.com)
6  *   Dietmar Maurer (dietmar@ximian.com)
7  *
8  * (C) 2003 Ximian, Inc.
9  * Copyright 2003-2011 Novell, Inc (http://www.novell.com)
10  * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
11  */
12 #include "mini.h"
13 #include <string.h>
14
15 #include <mono/metadata/abi-details.h>
16 #include <mono/metadata/appdomain.h>
17 #include <mono/metadata/debug-helpers.h>
18 #include <mono/utils/mono-mmap.h>
19 #include <mono/utils/mono-hwcap-arm.h>
20
21 #include "mini-arm.h"
22 #include "cpu-arm.h"
23 #include "trace.h"
24 #include "ir-emit.h"
25 #include "debugger-agent.h"
26 #include "mini-gc.h"
27 #include "mono/arch/arm/arm-vfp-codegen.h"
28
29 /* Sanity check: This makes no sense */
30 #if defined(ARM_FPU_NONE) && (defined(ARM_FPU_VFP) || defined(ARM_FPU_VFP_HARD))
31 #error "ARM_FPU_NONE is defined while one of ARM_FPU_VFP/ARM_FPU_VFP_HARD is defined"
32 #endif
33
34 /*
35  * IS_SOFT_FLOAT: Is full software floating point used?
36  * IS_HARD_FLOAT: Is full hardware floating point used?
37  * IS_VFP: Is hardware floating point with software ABI used?
38  *
39  * These are not necessarily constants, e.g. IS_SOFT_FLOAT and
40  * IS_VFP may delegate to mono_arch_is_soft_float ().
41  */
42
43 #if defined(ARM_FPU_VFP_HARD)
44 #define IS_SOFT_FLOAT (FALSE)
45 #define IS_HARD_FLOAT (TRUE)
46 #define IS_VFP (TRUE)
47 #elif defined(ARM_FPU_NONE)
48 #define IS_SOFT_FLOAT (mono_arch_is_soft_float ())
49 #define IS_HARD_FLOAT (FALSE)
50 #define IS_VFP (!mono_arch_is_soft_float ())
51 #else
52 #define IS_SOFT_FLOAT (FALSE)
53 #define IS_HARD_FLOAT (FALSE)
54 #define IS_VFP (TRUE)
55 #endif
56
57 #if defined(__ARM_EABI__) && defined(__linux__) && !defined(PLATFORM_ANDROID) && !defined(__native_client__)
58 #define HAVE_AEABI_READ_TP 1
59 #endif
60
61 #ifdef __native_client_codegen__
62 const guint kNaClAlignment = kNaClAlignmentARM;
63 const guint kNaClAlignmentMask = kNaClAlignmentMaskARM;
64 gint8 nacl_align_byte = -1; /* 0xff */
65
66 guint8 *
67 mono_arch_nacl_pad (guint8 *code, int pad)
68 {
69   /* Not yet properly implemented. */
70   g_assert_not_reached ();
71   return code;
72 }
73
74 guint8 *
75 mono_arch_nacl_skip_nops (guint8 *code)
76 {
77   /* Not yet properly implemented. */
78   g_assert_not_reached ();
79   return code;
80 }
81
82 #endif /* __native_client_codegen__ */
83
84 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
85
86 #if __APPLE__
87 void sys_icache_invalidate (void *start, size_t len);
88 #endif
89
90 /* This mutex protects architecture specific caches */
91 #define mono_mini_arch_lock() mono_mutex_lock (&mini_arch_mutex)
92 #define mono_mini_arch_unlock() mono_mutex_unlock (&mini_arch_mutex)
93 static mono_mutex_t mini_arch_mutex;
94
95 static gboolean v5_supported = FALSE;
96 static gboolean v6_supported = FALSE;
97 static gboolean v7_supported = FALSE;
98 static gboolean v7s_supported = FALSE;
99 static gboolean thumb_supported = FALSE;
100 static gboolean thumb2_supported = FALSE;
101 /*
102  * Whenever to use the ARM EABI
103  */
104 static gboolean eabi_supported = FALSE;
105
106 /* 
107  * Whenever to use the iphone ABI extensions:
108  * http://developer.apple.com/library/ios/documentation/Xcode/Conceptual/iPhoneOSABIReference/index.html
109  * Basically, r7 is used as a frame pointer and it should point to the saved r7 + lr.
110  * This is required for debugging/profiling tools to work, but it has some overhead so it should
111  * only be turned on in debug builds.
112  */
113 static gboolean iphone_abi = FALSE;
114
115 /*
116  * The FPU we are generating code for. This is NOT runtime configurable right now,
117  * since some things like MONO_ARCH_CALLEE_FREGS still depend on defines.
118  */
119 static MonoArmFPU arm_fpu;
120
121 #if defined(ARM_FPU_VFP_HARD)
122 /*
123  * On armhf, d0-d7 are used for argument passing and d8-d15
124  * must be preserved across calls, which leaves us no room
125  * for scratch registers. So we use d14-d15 but back up their
126  * previous contents to a stack slot before using them - see
127  * mono_arm_emit_vfp_scratch_save/_restore ().
128  */
129 static int vfp_scratch1 = ARM_VFP_D14;
130 static int vfp_scratch2 = ARM_VFP_D15;
131 #else
132 /*
133  * On armel, d0-d7 do not need to be preserved, so we can
134  * freely make use of them as scratch registers.
135  */
136 static int vfp_scratch1 = ARM_VFP_D0;
137 static int vfp_scratch2 = ARM_VFP_D1;
138 #endif
139
140 static int i8_align;
141
142 static volatile int ss_trigger_var = 0;
143
144 static gpointer single_step_func_wrapper;
145 static gpointer breakpoint_func_wrapper;
146
147 /*
148  * The code generated for sequence points reads from this location, which is
149  * made read-only when single stepping is enabled.
150  */
151 static gpointer ss_trigger_page;
152
153 /* Enabled breakpoints read from this trigger page */
154 static gpointer bp_trigger_page;
155
156 /*
157  * TODO:
158  * floating point support: on ARM it is a mess, there are at least 3
159  * different setups, each of which binary incompat with the other.
160  * 1) FPA: old and ugly, but unfortunately what current distros use
161  *    the double binary format has the two words swapped. 8 double registers.
162  *    Implemented usually by kernel emulation.
163  * 2) softfloat: the compiler emulates all the fp ops. Usually uses the
164  *    ugly swapped double format (I guess a softfloat-vfp exists, too, though).
165  * 3) VFP: the new and actually sensible and useful FP support. Implemented
166  *    in HW or kernel-emulated, requires new tools. I think this is what symbian uses.
167  *
168  * We do not care about FPA. We will support soft float and VFP.
169  */
170 int mono_exc_esp_offset = 0;
171
172 #define arm_is_imm12(v) ((v) > -4096 && (v) < 4096)
173 #define arm_is_imm8(v) ((v) > -256 && (v) < 256)
174 #define arm_is_fpimm8(v) ((v) >= -1020 && (v) <= 1020)
175
176 #define LDR_MASK ((0xf << ARMCOND_SHIFT) | (3 << 26) | (1 << 22) | (1 << 20) | (15 << 12))
177 #define LDR_PC_VAL ((ARMCOND_AL << ARMCOND_SHIFT) | (1 << 26) | (0 << 22) | (1 << 20) | (15 << 12))
178 #define IS_LDR_PC(val) (((val) & LDR_MASK) == LDR_PC_VAL)
179
180 #define ADD_LR_PC_4 ((ARMCOND_AL << ARMCOND_SHIFT) | (1 << 25) | (1 << 23) | (ARMREG_PC << 16) | (ARMREG_LR << 12) | 4)
181 #define MOV_LR_PC ((ARMCOND_AL << ARMCOND_SHIFT) | (1 << 24) | (0xa << 20) |  (ARMREG_LR << 12) | ARMREG_PC)
182 //#define DEBUG_IMT 0
183  
184 /* A variant of ARM_LDR_IMM which can handle large offsets */
185 #define ARM_LDR_IMM_GENERAL(code, dreg, basereg, offset, scratch_reg) do { \
186         if (arm_is_imm12 ((offset))) { \
187                 ARM_LDR_IMM (code, (dreg), (basereg), (offset));        \
188         } else {                                                                                                \
189                 g_assert ((scratch_reg) != (basereg));                                     \
190                 code = mono_arm_emit_load_imm (code, (scratch_reg), (offset));  \
191                 ARM_LDR_REG_REG (code, (dreg), (basereg), (scratch_reg));               \
192         }                                                                                                                                       \
193         } while (0)
194
195 #define ARM_STR_IMM_GENERAL(code, dreg, basereg, offset, scratch_reg) do {      \
196         if (arm_is_imm12 ((offset))) { \
197                 ARM_STR_IMM (code, (dreg), (basereg), (offset));        \
198         } else {                                                                                                \
199                 g_assert ((scratch_reg) != (basereg));                                     \
200                 code = mono_arm_emit_load_imm (code, (scratch_reg), (offset));  \
201                 ARM_STR_REG_REG (code, (dreg), (basereg), (scratch_reg));               \
202         }                                                                                                                                       \
203         } while (0)
204
205 #ifndef DISABLE_JIT
206 static void mono_arch_compute_omit_fp (MonoCompile *cfg);
207 #endif
208
209 const char*
210 mono_arch_regname (int reg)
211 {
212         static const char * rnames[] = {
213                 "arm_r0", "arm_r1", "arm_r2", "arm_r3", "arm_v1",
214                 "arm_v2", "arm_v3", "arm_v4", "arm_v5", "arm_v6",
215                 "arm_v7", "arm_fp", "arm_ip", "arm_sp", "arm_lr",
216                 "arm_pc"
217         };
218         if (reg >= 0 && reg < 16)
219                 return rnames [reg];
220         return "unknown";
221 }
222
223 const char*
224 mono_arch_fregname (int reg)
225 {
226         static const char * rnames[] = {
227                 "arm_f0", "arm_f1", "arm_f2", "arm_f3", "arm_f4",
228                 "arm_f5", "arm_f6", "arm_f7", "arm_f8", "arm_f9",
229                 "arm_f10", "arm_f11", "arm_f12", "arm_f13", "arm_f14",
230                 "arm_f15", "arm_f16", "arm_f17", "arm_f18", "arm_f19",
231                 "arm_f20", "arm_f21", "arm_f22", "arm_f23", "arm_f24",
232                 "arm_f25", "arm_f26", "arm_f27", "arm_f28", "arm_f29",
233                 "arm_f30", "arm_f31"
234         };
235         if (reg >= 0 && reg < 32)
236                 return rnames [reg];
237         return "unknown";
238 }
239
240
241 #ifndef DISABLE_JIT
242 static guint8*
243 emit_big_add (guint8 *code, int dreg, int sreg, int imm)
244 {
245         int imm8, rot_amount;
246         if ((imm8 = mono_arm_is_rotated_imm8 (imm, &rot_amount)) >= 0) {
247                 ARM_ADD_REG_IMM (code, dreg, sreg, imm8, rot_amount);
248                 return code;
249         }
250         g_assert (dreg != sreg);
251         code = mono_arm_emit_load_imm (code, dreg, imm);
252         ARM_ADD_REG_REG (code, dreg, dreg, sreg);
253         return code;
254 }
255
256 static guint8*
257 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
258 {
259         /* we can use r0-r3, since this is called only for incoming args on the stack */
260         if (size > sizeof (gpointer) * 4) {
261                 guint8 *start_loop;
262                 code = emit_big_add (code, ARMREG_R0, sreg, soffset);
263                 code = emit_big_add (code, ARMREG_R1, dreg, doffset);
264                 start_loop = code = mono_arm_emit_load_imm (code, ARMREG_R2, size);
265                 ARM_LDR_IMM (code, ARMREG_R3, ARMREG_R0, 0);
266                 ARM_STR_IMM (code, ARMREG_R3, ARMREG_R1, 0);
267                 ARM_ADD_REG_IMM8 (code, ARMREG_R0, ARMREG_R0, 4);
268                 ARM_ADD_REG_IMM8 (code, ARMREG_R1, ARMREG_R1, 4);
269                 ARM_SUBS_REG_IMM8 (code, ARMREG_R2, ARMREG_R2, 4);
270                 ARM_B_COND (code, ARMCOND_NE, 0);
271                 arm_patch (code - 4, start_loop);
272                 return code;
273         }
274         if (arm_is_imm12 (doffset) && arm_is_imm12 (doffset + size) &&
275                         arm_is_imm12 (soffset) && arm_is_imm12 (soffset + size)) {
276                 while (size >= 4) {
277                         ARM_LDR_IMM (code, ARMREG_LR, sreg, soffset);
278                         ARM_STR_IMM (code, ARMREG_LR, dreg, doffset);
279                         doffset += 4;
280                         soffset += 4;
281                         size -= 4;
282                 }
283         } else if (size) {
284                 code = emit_big_add (code, ARMREG_R0, sreg, soffset);
285                 code = emit_big_add (code, ARMREG_R1, dreg, doffset);
286                 doffset = soffset = 0;
287                 while (size >= 4) {
288                         ARM_LDR_IMM (code, ARMREG_LR, ARMREG_R0, soffset);
289                         ARM_STR_IMM (code, ARMREG_LR, ARMREG_R1, doffset);
290                         doffset += 4;
291                         soffset += 4;
292                         size -= 4;
293                 }
294         }
295         g_assert (size == 0);
296         return code;
297 }
298
299 static guint8*
300 emit_call_reg (guint8 *code, int reg)
301 {
302         if (v5_supported) {
303                 ARM_BLX_REG (code, reg);
304         } else {
305 #ifdef USE_JUMP_TABLES
306                 g_assert_not_reached ();
307 #endif
308                 ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC);
309                 if (thumb_supported)
310                         ARM_BX (code, reg);
311                 else
312                         ARM_MOV_REG_REG (code, ARMREG_PC, reg);
313         }
314         return code;
315 }
316
317 static guint8*
318 emit_call_seq (MonoCompile *cfg, guint8 *code)
319 {
320 #ifdef USE_JUMP_TABLES
321         code = mono_arm_patchable_bl (code, ARMCOND_AL);
322 #else
323         if (cfg->method->dynamic) {
324                 ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0);
325                 ARM_B (code, 0);
326                 *(gpointer*)code = NULL;
327                 code += 4;
328                 code = emit_call_reg (code, ARMREG_IP);
329         } else {
330                 ARM_BL (code, 0);
331         }
332 #endif
333         return code;
334 }
335
336 guint8*
337 mono_arm_patchable_b (guint8 *code, int cond)
338 {
339 #ifdef USE_JUMP_TABLES
340         gpointer *jte;
341
342         jte = mono_jumptable_add_entry ();
343         code = mono_arm_load_jumptable_entry (code, jte, ARMREG_IP);
344         ARM_BX_COND (code, cond, ARMREG_IP);
345 #else
346         ARM_B_COND (code, cond, 0);
347 #endif
348         return code;
349 }
350
351 guint8*
352 mono_arm_patchable_bl (guint8 *code, int cond)
353 {
354 #ifdef USE_JUMP_TABLES
355         gpointer *jte;
356
357         jte = mono_jumptable_add_entry ();
358         code = mono_arm_load_jumptable_entry (code, jte,  ARMREG_IP);
359         ARM_BLX_REG_COND (code, cond, ARMREG_IP);
360 #else
361         ARM_BL_COND (code, cond, 0);
362 #endif
363         return code;
364 }
365
366 #ifdef USE_JUMP_TABLES
367 guint8*
368 mono_arm_load_jumptable_entry_addr (guint8 *code, gpointer *jte, ARMReg reg)
369 {
370         ARM_MOVW_REG_IMM (code, reg, GPOINTER_TO_UINT(jte) & 0xffff);
371         ARM_MOVT_REG_IMM (code, reg, (GPOINTER_TO_UINT(jte) >> 16) & 0xffff);
372         return code;
373 }
374
375 guint8*
376 mono_arm_load_jumptable_entry (guint8 *code, gpointer* jte, ARMReg reg)
377 {
378         code = mono_arm_load_jumptable_entry_addr (code, jte, reg);
379         ARM_LDR_IMM (code, reg, reg, 0);
380         return code;
381 }
382 #endif
383
384 static guint8*
385 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
386 {
387         switch (ins->opcode) {
388         case OP_FCALL:
389         case OP_FCALL_REG:
390         case OP_FCALL_MEMBASE:
391                 if (IS_VFP) {
392                         if (((MonoCallInst*)ins)->signature->ret->type == MONO_TYPE_R4) {
393                                 if (IS_HARD_FLOAT) {
394                                         ARM_CVTS (code, ins->dreg, ARM_VFP_F0);
395                                 } else {
396                                         ARM_FMSR (code, ins->dreg, ARMREG_R0);
397                                         ARM_CVTS (code, ins->dreg, ins->dreg);
398                                 }
399                         } else {
400                                 if (IS_HARD_FLOAT) {
401                                         ARM_CPYD (code, ins->dreg, ARM_VFP_D0);
402                                 } else {
403                                         ARM_FMDRR (code, ARMREG_R0, ARMREG_R1, ins->dreg);
404                                 }
405                         }
406                 }
407                 break;
408         }
409
410         return code;
411 }
412
413 /*
414  * emit_save_lmf:
415  *
416  *   Emit code to push an LMF structure on the LMF stack.
417  * On arm, this is intermixed with the initialization of other fields of the structure.
418  */
419 static guint8*
420 emit_save_lmf (MonoCompile *cfg, guint8 *code, gint32 lmf_offset)
421 {
422         gboolean get_lmf_fast = FALSE;
423         int i;
424
425 #ifdef HAVE_AEABI_READ_TP
426         gint32 lmf_addr_tls_offset = mono_get_lmf_addr_tls_offset ();
427
428         if (lmf_addr_tls_offset != -1) {
429                 get_lmf_fast = TRUE;
430
431                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
432                                                          (gpointer)"__aeabi_read_tp");
433                 code = emit_call_seq (cfg, code);
434
435                 ARM_LDR_IMM (code, ARMREG_R0, ARMREG_R0, lmf_addr_tls_offset);
436                 get_lmf_fast = TRUE;
437         }
438 #endif
439
440 #ifdef TARGET_IOS
441         if (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
442                 int lmf_offset;
443
444                 /* Inline mono_get_lmf_addr () */
445                 /* jit_tls = pthread_getspecific (mono_jit_tls_id); lmf_addr = &jit_tls->lmf; */
446
447                 /* Load mono_jit_tls_id */
448                 /* OP_AOTCONST */
449                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_JIT_TLS_ID, NULL);
450                 ARM_LDR_IMM (code, ARMREG_R0, ARMREG_PC, 0);
451                 ARM_B (code, 0);
452                 *(gpointer*)code = NULL;
453                 code += 4;
454                 ARM_LDR_REG_REG (code, ARMREG_R0, ARMREG_PC, ARMREG_R0);
455                 /* call pthread_getspecific () */
456                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
457                                                          (gpointer)"pthread_getspecific");
458                 code = emit_call_seq (cfg, code);
459                 /* lmf_addr = &jit_tls->lmf */
460                 lmf_offset = MONO_STRUCT_OFFSET (MonoJitTlsData, lmf);
461                 g_assert (arm_is_imm8 (lmf_offset));
462                 ARM_ADD_REG_IMM (code, ARMREG_R0, ARMREG_R0, lmf_offset, 0);
463
464                 get_lmf_fast = TRUE;
465         }
466 #endif
467
468         if (!get_lmf_fast) {
469                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
470                                                          (gpointer)"mono_get_lmf_addr");
471                 code = emit_call_seq (cfg, code);
472         }
473         /* we build the MonoLMF structure on the stack - see mini-arm.h */
474         /* lmf_offset is the offset from the previous stack pointer,
475          * alloc_size is the total stack space allocated, so the offset
476          * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
477          * The pointer to the struct is put in r1 (new_lmf).
478          * ip is used as scratch
479          * The callee-saved registers are already in the MonoLMF structure
480          */
481         code = emit_big_add (code, ARMREG_R1, ARMREG_SP, lmf_offset);
482         /* r0 is the result from mono_get_lmf_addr () */
483         ARM_STR_IMM (code, ARMREG_R0, ARMREG_R1, MONO_STRUCT_OFFSET (MonoLMF, lmf_addr));
484         /* new_lmf->previous_lmf = *lmf_addr */
485         ARM_LDR_IMM (code, ARMREG_IP, ARMREG_R0, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
486         ARM_STR_IMM (code, ARMREG_IP, ARMREG_R1, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
487         /* *(lmf_addr) = r1 */
488         ARM_STR_IMM (code, ARMREG_R1, ARMREG_R0, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
489         /* Skip method (only needed for trampoline LMF frames) */
490         ARM_STR_IMM (code, ARMREG_SP, ARMREG_R1, MONO_STRUCT_OFFSET (MonoLMF, sp));
491         ARM_STR_IMM (code, ARMREG_FP, ARMREG_R1, MONO_STRUCT_OFFSET (MonoLMF, fp));
492         /* save the current IP */
493         ARM_MOV_REG_REG (code, ARMREG_IP, ARMREG_PC);
494         ARM_STR_IMM (code, ARMREG_IP, ARMREG_R1, MONO_STRUCT_OFFSET (MonoLMF, ip));
495
496         for (i = 0; i < sizeof (MonoLMF); i += sizeof (mgreg_t))
497                 mini_gc_set_slot_type_from_fp (cfg, lmf_offset + i, SLOT_NOREF);
498
499         return code;
500 }
501
502 typedef struct {
503         gint32 vreg;
504         gint32 hreg;
505 } FloatArgData;
506
507 static guint8 *
508 emit_float_args (MonoCompile *cfg, MonoCallInst *inst, guint8 *code, int *max_len, guint *offset)
509 {
510         GSList *list;
511
512         for (list = inst->float_args; list; list = list->next) {
513                 FloatArgData *fad = list->data;
514                 MonoInst *var = get_vreg_to_inst (cfg, fad->vreg);
515                 gboolean imm = arm_is_fpimm8 (var->inst_offset);
516
517                 /* 4+1 insns for emit_big_add () and 1 for FLDS. */
518                 if (!imm)
519                         *max_len += 20 + 4;
520
521                 *max_len += 4;
522
523                 if (*offset + *max_len > cfg->code_size) {
524                         cfg->code_size += *max_len;
525                         cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
526
527                         code = cfg->native_code + *offset;
528                 }
529
530                 if (!imm) {
531                         code = emit_big_add (code, ARMREG_LR, var->inst_basereg, var->inst_offset);
532                         ARM_FLDS (code, fad->hreg, ARMREG_LR, 0);
533                 } else
534                         ARM_FLDS (code, fad->hreg, var->inst_basereg, var->inst_offset);
535
536                 *offset = code - cfg->native_code;
537         }
538
539         return code;
540 }
541
542 static guint8 *
543 mono_arm_emit_vfp_scratch_save (MonoCompile *cfg, guint8 *code, int reg)
544 {
545         MonoInst *inst;
546
547         g_assert (reg == vfp_scratch1 || reg == vfp_scratch2);
548
549         inst = (MonoInst *) cfg->arch.vfp_scratch_slots [reg == vfp_scratch1 ? 0 : 1];
550
551         if (IS_HARD_FLOAT) {
552                 if (!arm_is_fpimm8 (inst->inst_offset)) {
553                         code = emit_big_add (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset);
554                         ARM_FSTD (code, reg, ARMREG_LR, 0);
555                 } else
556                         ARM_FSTD (code, reg, inst->inst_basereg, inst->inst_offset);
557         }
558
559         return code;
560 }
561
562 static guint8 *
563 mono_arm_emit_vfp_scratch_restore (MonoCompile *cfg, guint8 *code, int reg)
564 {
565         MonoInst *inst;
566
567         g_assert (reg == vfp_scratch1 || reg == vfp_scratch2);
568
569         inst = (MonoInst *) cfg->arch.vfp_scratch_slots [reg == vfp_scratch1 ? 0 : 1];
570
571         if (IS_HARD_FLOAT) {
572                 if (!arm_is_fpimm8 (inst->inst_offset)) {
573                         code = emit_big_add (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset);
574                         ARM_FLDD (code, reg, ARMREG_LR, 0);
575                 } else
576                         ARM_FLDD (code, reg, inst->inst_basereg, inst->inst_offset);
577         }
578
579         return code;
580 }
581
582 /*
583  * emit_restore_lmf:
584  *
585  *   Emit code to pop an LMF structure from the LMF stack.
586  */
587 static guint8*
588 emit_restore_lmf (MonoCompile *cfg, guint8 *code, gint32 lmf_offset)
589 {
590         int basereg, offset;
591
592         if (lmf_offset < 32) {
593                 basereg = cfg->frame_reg;
594                 offset = lmf_offset;
595         } else {
596                 basereg = ARMREG_R2;
597                 offset = 0;
598                 code = emit_big_add (code, ARMREG_R2, cfg->frame_reg, lmf_offset);
599         }
600
601         /* ip = previous_lmf */
602         ARM_LDR_IMM (code, ARMREG_IP, basereg, offset + MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
603         /* lr = lmf_addr */
604         ARM_LDR_IMM (code, ARMREG_LR, basereg, offset + MONO_STRUCT_OFFSET (MonoLMF, lmf_addr));
605         /* *(lmf_addr) = previous_lmf */
606         ARM_STR_IMM (code, ARMREG_IP, ARMREG_LR, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
607
608         return code;
609 }
610
611 #endif /* #ifndef DISABLE_JIT */
612
613 /*
614  * mono_arch_get_argument_info:
615  * @csig:  a method signature
616  * @param_count: the number of parameters to consider
617  * @arg_info: an array to store the result infos
618  *
619  * Gathers information on parameters such as size, alignment and
620  * padding. arg_info should be large enought to hold param_count + 1 entries. 
621  *
622  * Returns the size of the activation frame.
623  */
624 int
625 mono_arch_get_argument_info (MonoGenericSharingContext *gsctx, MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
626 {
627         int k, frame_size = 0;
628         guint32 size, align, pad;
629         int offset = 8;
630         MonoType *t;
631
632         t = mini_type_get_underlying_type (gsctx, csig->ret);
633         if (MONO_TYPE_ISSTRUCT (t)) {
634                 frame_size += sizeof (gpointer);
635                 offset += 4;
636         }
637
638         arg_info [0].offset = offset;
639
640         if (csig->hasthis) {
641                 frame_size += sizeof (gpointer);
642                 offset += 4;
643         }
644
645         arg_info [0].size = frame_size;
646
647         for (k = 0; k < param_count; k++) {
648                 size = mini_type_stack_size_full (NULL, csig->params [k], &align, csig->pinvoke);
649
650                 /* ignore alignment for now */
651                 align = 1;
652
653                 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1); 
654                 arg_info [k].pad = pad;
655                 frame_size += size;
656                 arg_info [k + 1].pad = 0;
657                 arg_info [k + 1].size = size;
658                 offset += pad;
659                 arg_info [k + 1].offset = offset;
660                 offset += size;
661         }
662
663         align = MONO_ARCH_FRAME_ALIGNMENT;
664         frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
665         arg_info [k].pad = pad;
666
667         return frame_size;
668 }
669
670 #define MAX_ARCH_DELEGATE_PARAMS 3
671
672 static gpointer
673 get_delegate_invoke_impl (gboolean has_target, gboolean param_count, guint32 *code_size)
674 {
675         guint8 *code, *start;
676
677         if (has_target) {
678                 start = code = mono_global_codeman_reserve (12);
679
680                 /* Replace the this argument with the target */
681                 ARM_LDR_IMM (code, ARMREG_IP, ARMREG_R0, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
682                 ARM_LDR_IMM (code, ARMREG_R0, ARMREG_R0, MONO_STRUCT_OFFSET (MonoDelegate, target));
683                 ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
684
685                 g_assert ((code - start) <= 12);
686
687                 mono_arch_flush_icache (start, 12);
688         } else {
689                 int size, i;
690
691                 size = 8 + param_count * 4;
692                 start = code = mono_global_codeman_reserve (size);
693
694                 ARM_LDR_IMM (code, ARMREG_IP, ARMREG_R0, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
695                 /* slide down the arguments */
696                 for (i = 0; i < param_count; ++i) {
697                         ARM_MOV_REG_REG (code, (ARMREG_R0 + i), (ARMREG_R0 + i + 1));
698                 }
699                 ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
700
701                 g_assert ((code - start) <= size);
702
703                 mono_arch_flush_icache (start, size);
704         }
705
706         if (code_size)
707                 *code_size = code - start;
708
709         return start;
710 }
711
712 /*
713  * mono_arch_get_delegate_invoke_impls:
714  *
715  *   Return a list of MonoAotTrampInfo structures for the delegate invoke impl
716  * trampolines.
717  */
718 GSList*
719 mono_arch_get_delegate_invoke_impls (void)
720 {
721         GSList *res = NULL;
722         guint8 *code;
723         guint32 code_len;
724         int i;
725         char *tramp_name;
726
727         code = get_delegate_invoke_impl (TRUE, 0, &code_len);
728         res = g_slist_prepend (res, mono_tramp_info_create ("delegate_invoke_impl_has_target", code, code_len, NULL, NULL));
729
730         for (i = 0; i <= MAX_ARCH_DELEGATE_PARAMS; ++i) {
731                 code = get_delegate_invoke_impl (FALSE, i, &code_len);
732                 tramp_name = g_strdup_printf ("delegate_invoke_impl_target_%d", i);
733                 res = g_slist_prepend (res, mono_tramp_info_create (tramp_name, code, code_len, NULL, NULL));
734                 g_free (tramp_name);
735         }
736
737         return res;
738 }
739
740 gpointer
741 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
742 {
743         guint8 *code, *start;
744         MonoType *sig_ret;
745
746         /* FIXME: Support more cases */
747         sig_ret = mini_type_get_underlying_type (NULL, sig->ret);
748         if (MONO_TYPE_ISSTRUCT (sig_ret))
749                 return NULL;
750
751         if (has_target) {
752                 static guint8* cached = NULL;
753                 mono_mini_arch_lock ();
754                 if (cached) {
755                         mono_mini_arch_unlock ();
756                         return cached;
757                 }
758
759                 if (mono_aot_only)
760                         start = mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
761                 else
762                         start = get_delegate_invoke_impl (TRUE, 0, NULL);
763                 cached = start;
764                 mono_mini_arch_unlock ();
765                 return cached;
766         } else {
767                 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
768                 int i;
769
770                 if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
771                         return NULL;
772                 for (i = 0; i < sig->param_count; ++i)
773                         if (!mono_is_regsize_var (sig->params [i]))
774                                 return NULL;
775
776                 mono_mini_arch_lock ();
777                 code = cache [sig->param_count];
778                 if (code) {
779                         mono_mini_arch_unlock ();
780                         return code;
781                 }
782
783                 if (mono_aot_only) {
784                         char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", sig->param_count);
785                         start = mono_aot_get_trampoline (name);
786                         g_free (name);
787                 } else {
788                         start = get_delegate_invoke_impl (FALSE, sig->param_count, NULL);
789                 }
790                 cache [sig->param_count] = start;
791                 mono_mini_arch_unlock ();
792                 return start;
793         }
794
795         return NULL;
796 }
797
798 gpointer
799 mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method, int offset, gboolean load_imt_reg)
800 {
801         return NULL;
802 }
803
804 gpointer
805 mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code)
806 {
807         return (gpointer)regs [ARMREG_R0];
808 }
809
810 /*
811  * Initialize the cpu to execute managed code.
812  */
813 void
814 mono_arch_cpu_init (void)
815 {
816         i8_align = MONO_ABI_ALIGNOF (gint64);
817 #ifdef MONO_CROSS_COMPILE
818         /* Need to set the alignment of i8 since it can different on the target */
819 #ifdef TARGET_ANDROID
820         /* linux gnueabi */
821         mono_type_set_alignment (MONO_TYPE_I8, i8_align);
822 #endif
823 #endif
824 }
825
826 static gpointer
827 create_function_wrapper (gpointer function)
828 {
829         guint8 *start, *code;
830
831         start = code = mono_global_codeman_reserve (96);
832
833         /*
834          * Construct the MonoContext structure on the stack.
835          */
836
837         ARM_SUB_REG_IMM8 (code, ARMREG_SP, ARMREG_SP, sizeof (MonoContext));
838
839         /* save ip, lr and pc into their correspodings ctx.regs slots. */
840         ARM_STR_IMM (code, ARMREG_IP, ARMREG_SP, MONO_STRUCT_OFFSET (MonoContext, regs) + sizeof (mgreg_t) * ARMREG_IP);
841         ARM_STR_IMM (code, ARMREG_LR, ARMREG_SP, MONO_STRUCT_OFFSET (MonoContext, regs) + 4 * ARMREG_LR);
842         ARM_STR_IMM (code, ARMREG_LR, ARMREG_SP, MONO_STRUCT_OFFSET (MonoContext, regs) + 4 * ARMREG_PC);
843
844         /* save r0..r10 and fp */
845         ARM_ADD_REG_IMM8 (code, ARMREG_IP, ARMREG_SP, MONO_STRUCT_OFFSET (MonoContext, regs));
846         ARM_STM (code, ARMREG_IP, 0x0fff);
847
848         /* now we can update fp. */
849         ARM_MOV_REG_REG (code, ARMREG_FP, ARMREG_SP);
850
851         /* make ctx.esp hold the actual value of sp at the beginning of this method. */
852         ARM_ADD_REG_IMM8 (code, ARMREG_R0, ARMREG_FP, sizeof (MonoContext));
853         ARM_STR_IMM (code, ARMREG_R0, ARMREG_IP, 4 * ARMREG_SP);
854         ARM_STR_IMM (code, ARMREG_R0, ARMREG_FP, MONO_STRUCT_OFFSET (MonoContext, regs) + 4 * ARMREG_SP);
855
856         /* make ctx.eip hold the address of the call. */
857         ARM_SUB_REG_IMM8 (code, ARMREG_LR, ARMREG_LR, 4);
858         ARM_STR_IMM (code, ARMREG_LR, ARMREG_SP, MONO_STRUCT_OFFSET (MonoContext, pc));
859
860         /* r0 now points to the MonoContext */
861         ARM_MOV_REG_REG (code, ARMREG_R0, ARMREG_FP);
862
863         /* call */
864 #ifdef USE_JUMP_TABLES
865         {
866                 gpointer *jte = mono_jumptable_add_entry ();
867                 code = mono_arm_load_jumptable_entry (code, jte, ARMREG_IP);
868                 jte [0] = function;
869         }
870 #else
871         ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0);
872         ARM_B (code, 0);
873         *(gpointer*)code = function;
874         code += 4;
875 #endif
876         ARM_BLX_REG (code, ARMREG_IP);
877
878         /* we're back; save ctx.eip and ctx.esp into the corresponding regs slots. */
879         ARM_LDR_IMM (code, ARMREG_R0, ARMREG_FP, MONO_STRUCT_OFFSET (MonoContext, pc));
880         ARM_STR_IMM (code, ARMREG_R0, ARMREG_FP, MONO_STRUCT_OFFSET (MonoContext, regs) + 4 * ARMREG_LR);
881         ARM_STR_IMM (code, ARMREG_R0, ARMREG_FP, MONO_STRUCT_OFFSET (MonoContext, regs) + 4 * ARMREG_PC);
882
883         /* make ip point to the regs array, then restore everything, including pc. */
884         ARM_ADD_REG_IMM8 (code, ARMREG_IP, ARMREG_FP, MONO_STRUCT_OFFSET (MonoContext, regs));
885         ARM_LDM (code, ARMREG_IP, 0xffff);
886
887         mono_arch_flush_icache (start, code - start);
888
889         return start;
890 }
891
892 /*
893  * Initialize architecture specific code.
894  */
895 void
896 mono_arch_init (void)
897 {
898         const char *cpu_arch;
899
900         mono_mutex_init_recursive (&mini_arch_mutex);
901 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
902         if (mini_get_debug_options ()->soft_breakpoints) {
903                 single_step_func_wrapper = create_function_wrapper (debugger_agent_single_step_from_context);
904                 breakpoint_func_wrapper = create_function_wrapper (debugger_agent_breakpoint_from_context);
905         } else {
906 #else
907         {
908 #endif
909                 ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
910                 bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
911                 mono_mprotect (bp_trigger_page, mono_pagesize (), 0);
912         }
913
914         mono_aot_register_jit_icall ("mono_arm_throw_exception", mono_arm_throw_exception);
915         mono_aot_register_jit_icall ("mono_arm_throw_exception_by_token", mono_arm_throw_exception_by_token);
916         mono_aot_register_jit_icall ("mono_arm_resume_unwind", mono_arm_resume_unwind);
917 #if defined(ENABLE_GSHAREDVT)
918         mono_aot_register_jit_icall ("mono_arm_start_gsharedvt_call", mono_arm_start_gsharedvt_call);
919 #endif
920
921 #if defined(__ARM_EABI__)
922         eabi_supported = TRUE;
923 #endif
924
925 #if defined(ARM_FPU_VFP_HARD)
926         arm_fpu = MONO_ARM_FPU_VFP_HARD;
927 #else
928         arm_fpu = MONO_ARM_FPU_VFP;
929
930 #if defined(ARM_FPU_NONE) && !defined(__APPLE__)
931         /* If we're compiling with a soft float fallback and it
932            turns out that no VFP unit is available, we need to
933            switch to soft float. We don't do this for iOS, since
934            iOS devices always have a VFP unit. */
935         if (!mono_hwcap_arm_has_vfp)
936                 arm_fpu = MONO_ARM_FPU_NONE;
937 #endif
938 #endif
939
940         v5_supported = mono_hwcap_arm_is_v5;
941         v6_supported = mono_hwcap_arm_is_v6;
942         v7_supported = mono_hwcap_arm_is_v7;
943         v7s_supported = mono_hwcap_arm_is_v7s;
944
945 #if defined(__APPLE__)
946         /* iOS is special-cased here because we don't yet
947            have a way to properly detect CPU features on it. */
948         thumb_supported = TRUE;
949         iphone_abi = TRUE;
950 #else
951         thumb_supported = mono_hwcap_arm_has_thumb;
952         thumb2_supported = mono_hwcap_arm_has_thumb2;
953 #endif
954
955         /* Format: armv(5|6|7[s])[-thumb[2]] */
956         cpu_arch = g_getenv ("MONO_CPU_ARCH");
957
958         /* Do this here so it overrides any detection. */
959         if (cpu_arch) {
960                 if (strncmp (cpu_arch, "armv", 4) == 0) {
961                         v5_supported = cpu_arch [4] >= '5';
962                         v6_supported = cpu_arch [4] >= '6';
963                         v7_supported = cpu_arch [4] >= '7';
964                         v7s_supported = strncmp (cpu_arch, "armv7s", 6) == 0;
965                 }
966
967                 thumb_supported = strstr (cpu_arch, "thumb") != NULL;
968                 thumb2_supported = strstr (cpu_arch, "thumb2") != NULL;
969         }
970 }
971
972 /*
973  * Cleanup architecture specific code.
974  */
975 void
976 mono_arch_cleanup (void)
977 {
978 }
979
980 /*
981  * This function returns the optimizations supported on this cpu.
982  */
983 guint32
984 mono_arch_cpu_optimizations (guint32 *exclude_mask)
985 {
986         /* no arm-specific optimizations yet */
987         *exclude_mask = 0;
988         return 0;
989 }
990
991 /*
992  * This function test for all SIMD functions supported.
993  *
994  * Returns a bitmask corresponding to all supported versions.
995  *
996  */
997 guint32
998 mono_arch_cpu_enumerate_simd_versions (void)
999 {
1000         /* SIMD is currently unimplemented */
1001         return 0;
1002 }
1003
1004
1005 #ifndef DISABLE_JIT
1006
1007 gboolean
1008 mono_arch_opcode_needs_emulation (MonoCompile *cfg, int opcode)
1009 {
1010         if (v7s_supported) {
1011                 switch (opcode) {
1012                 case OP_IDIV:
1013                 case OP_IREM:
1014                 case OP_IDIV_UN:
1015                 case OP_IREM_UN:
1016                         return FALSE;
1017                 default:
1018                         break;
1019                 }
1020         }
1021         return TRUE;
1022 }
1023
1024 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
1025 gboolean
1026 mono_arch_is_soft_float (void)
1027 {
1028         return arm_fpu == MONO_ARM_FPU_NONE;
1029 }
1030 #endif
1031
1032 gboolean
1033 mono_arm_is_hard_float (void)
1034 {
1035         return arm_fpu == MONO_ARM_FPU_VFP_HARD;
1036 }
1037
1038 static gboolean
1039 is_regsize_var (MonoGenericSharingContext *gsctx, MonoType *t) {
1040         if (t->byref)
1041                 return TRUE;
1042         t = mini_type_get_underlying_type (gsctx, t);
1043         switch (t->type) {
1044         case MONO_TYPE_I4:
1045         case MONO_TYPE_U4:
1046         case MONO_TYPE_I:
1047         case MONO_TYPE_U:
1048         case MONO_TYPE_PTR:
1049         case MONO_TYPE_FNPTR:
1050                 return TRUE;
1051         case MONO_TYPE_OBJECT:
1052         case MONO_TYPE_STRING:
1053         case MONO_TYPE_CLASS:
1054         case MONO_TYPE_SZARRAY:
1055         case MONO_TYPE_ARRAY:
1056                 return TRUE;
1057         case MONO_TYPE_GENERICINST:
1058                 if (!mono_type_generic_inst_is_valuetype (t))
1059                         return TRUE;
1060                 return FALSE;
1061         case MONO_TYPE_VALUETYPE:
1062                 return FALSE;
1063         }
1064         return FALSE;
1065 }
1066
1067 GList *
1068 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
1069 {
1070         GList *vars = NULL;
1071         int i;
1072
1073         for (i = 0; i < cfg->num_varinfo; i++) {
1074                 MonoInst *ins = cfg->varinfo [i];
1075                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
1076
1077                 /* unused vars */
1078                 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
1079                         continue;
1080
1081                 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
1082                         continue;
1083
1084                 /* we can only allocate 32 bit values */
1085                 if (is_regsize_var (cfg->generic_sharing_context, ins->inst_vtype)) {
1086                         g_assert (MONO_VARINFO (cfg, i)->reg == -1);
1087                         g_assert (i == vmv->idx);
1088                         vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
1089                 }
1090         }
1091
1092         return vars;
1093 }
1094
1095 #define USE_EXTRA_TEMPS 0
1096
1097 GList *
1098 mono_arch_get_global_int_regs (MonoCompile *cfg)
1099 {
1100         GList *regs = NULL;
1101
1102         mono_arch_compute_omit_fp (cfg);
1103
1104         /* 
1105          * FIXME: Interface calls might go through a static rgctx trampoline which
1106          * sets V5, but it doesn't save it, so we need to save it ourselves, and
1107          * avoid using it.
1108          */
1109         if (cfg->flags & MONO_CFG_HAS_CALLS)
1110                 cfg->uses_rgctx_reg = TRUE;
1111
1112         if (cfg->arch.omit_fp)
1113                 regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_FP));
1114         regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V1));
1115         regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V2));
1116         regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V3));
1117         if (iphone_abi)
1118                 /* V4=R7 is used as a frame pointer, but V7=R10 is preserved */
1119                 regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V7));
1120         else
1121                 regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V4));
1122         if (!(cfg->compile_aot || cfg->uses_rgctx_reg || COMPILE_LLVM (cfg)))
1123                 /* V5 is reserved for passing the vtable/rgctx/IMT method */
1124                 regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V5));
1125         /*regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V6));*/
1126         /*regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V7));*/
1127
1128         return regs;
1129 }
1130
1131 /*
1132  * mono_arch_regalloc_cost:
1133  *
1134  *  Return the cost, in number of memory references, of the action of 
1135  * allocating the variable VMV into a register during global register
1136  * allocation.
1137  */
1138 guint32
1139 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
1140 {
1141         /* FIXME: */
1142         return 2;
1143 }
1144
1145 #endif /* #ifndef DISABLE_JIT */
1146
1147 #ifndef __GNUC_PREREQ
1148 #define __GNUC_PREREQ(maj, min) (0)
1149 #endif
1150
1151 void
1152 mono_arch_flush_icache (guint8 *code, gint size)
1153 {
1154 #if defined(__native_client__)
1155   // For Native Client we don't have to flush i-cache here,
1156   // as it's being done by dyncode interface.
1157 #else
1158
1159 #ifdef MONO_CROSS_COMPILE
1160 #elif __APPLE__
1161         sys_icache_invalidate (code, size);
1162 #elif __GNUC_PREREQ(4, 1)
1163         __clear_cache (code, code + size);
1164 #elif defined(PLATFORM_ANDROID)
1165         const int syscall = 0xf0002;
1166         __asm __volatile (
1167                 "mov     r0, %0\n"                      
1168                 "mov     r1, %1\n"
1169                 "mov     r7, %2\n"
1170                 "mov     r2, #0x0\n"
1171                 "svc     0x00000000\n"
1172                 :
1173                 :       "r" (code), "r" (code + size), "r" (syscall)
1174                 :       "r0", "r1", "r7", "r2"
1175                 );
1176 #else
1177         __asm __volatile ("mov r0, %0\n"
1178                         "mov r1, %1\n"
1179                         "mov r2, %2\n"
1180                         "swi 0x9f0002       @ sys_cacheflush"
1181                         : /* no outputs */
1182                         : "r" (code), "r" (code + size), "r" (0)
1183                         : "r0", "r1", "r3" );
1184 #endif
1185 #endif /* !__native_client__ */
1186 }
1187
1188 typedef enum {
1189         RegTypeNone,
1190         RegTypeGeneral,
1191         RegTypeIRegPair,
1192         RegTypeBase,
1193         RegTypeBaseGen,
1194         RegTypeFP,
1195         RegTypeStructByVal,
1196         RegTypeStructByAddr,
1197         /* gsharedvt argument passed by addr in greg */
1198         RegTypeGSharedVtInReg,
1199         /* gsharedvt argument passed by addr on stack */
1200         RegTypeGSharedVtOnStack,
1201 } ArgStorage;
1202
1203 typedef struct {
1204         gint32  offset;
1205         guint16 vtsize; /* in param area */
1206         guint8  reg;
1207         ArgStorage  storage;
1208         gint32  struct_size;
1209         guint8  size    : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
1210 } ArgInfo;
1211
1212 typedef struct {
1213         int nargs;
1214         guint32 stack_usage;
1215         gboolean vtype_retaddr;
1216         /* The index of the vret arg in the argument list */
1217         int vret_arg_index;
1218         ArgInfo ret;
1219         ArgInfo sig_cookie;
1220         ArgInfo args [1];
1221 } CallInfo;
1222
1223 #define DEBUG(a)
1224
1225 static void inline
1226 add_general (guint *gr, guint *stack_size, ArgInfo *ainfo, gboolean simple)
1227 {
1228         if (simple) {
1229                 if (*gr > ARMREG_R3) {
1230                         ainfo->size = 4;
1231                         ainfo->offset = *stack_size;
1232                         ainfo->reg = ARMREG_SP; /* in the caller */
1233                         ainfo->storage = RegTypeBase;
1234                         *stack_size += 4;
1235                 } else {
1236                         ainfo->storage = RegTypeGeneral;
1237                         ainfo->reg = *gr;
1238                 }
1239         } else {
1240                 gboolean split;
1241
1242                 if (eabi_supported)
1243                         split = i8_align == 4;
1244                 else
1245                         split = TRUE;
1246
1247                 ainfo->size = 8;
1248                 if (*gr == ARMREG_R3 && split) {
1249                         /* first word in r3 and the second on the stack */
1250                         ainfo->offset = *stack_size;
1251                         ainfo->reg = ARMREG_SP; /* in the caller */
1252                         ainfo->storage = RegTypeBaseGen;
1253                         *stack_size += 4;
1254                 } else if (*gr >= ARMREG_R3) {
1255                         if (eabi_supported) {
1256                                 /* darwin aligns longs to 4 byte only */
1257                                 if (i8_align == 8) {
1258                                         *stack_size += 7;
1259                                         *stack_size &= ~7;
1260                                 }
1261                         }
1262                         ainfo->offset = *stack_size;
1263                         ainfo->reg = ARMREG_SP; /* in the caller */
1264                         ainfo->storage = RegTypeBase;
1265                         *stack_size += 8;
1266                 } else {
1267                         if (eabi_supported) {
1268                                 if (i8_align == 8 && ((*gr) & 1))
1269                                         (*gr) ++;
1270                         }
1271                         ainfo->storage = RegTypeIRegPair;
1272                         ainfo->reg = *gr;
1273                 }
1274                 (*gr) ++;
1275         }
1276         (*gr) ++;
1277 }
1278
1279 static void inline
1280 add_float (guint *fpr, guint *stack_size, ArgInfo *ainfo, gboolean is_double, gint *float_spare)
1281 {
1282         /*
1283          * If we're calling a function like this:
1284          *
1285          * void foo(float a, double b, float c)
1286          *
1287          * We pass a in s0 and b in d1. That leaves us
1288          * with s1 being unused. The armhf ABI recognizes
1289          * this and requires register assignment to then
1290          * use that for the next single-precision arg,
1291          * i.e. c in this example. So float_spare either
1292          * tells us which reg to use for the next single-
1293          * precision arg, or it's -1, meaning use *fpr.
1294          *
1295          * Note that even though most of the JIT speaks
1296          * double-precision, fpr represents single-
1297          * precision registers.
1298          *
1299          * See parts 5.5 and 6.1.2 of the AAPCS for how
1300          * this all works.
1301          */
1302
1303         if (*fpr < ARM_VFP_F16 || (!is_double && *float_spare >= 0)) {
1304                 ainfo->storage = RegTypeFP;
1305
1306                 if (is_double) {
1307                         /*
1308                          * If we're passing a double-precision value
1309                          * and *fpr is odd (e.g. it's s1, s3, ...)
1310                          * we need to use the next even register. So
1311                          * we mark the current *fpr as a spare that
1312                          * can be used for the next single-precision
1313                          * value.
1314                          */
1315                         if (*fpr % 2) {
1316                                 *float_spare = *fpr;
1317                                 (*fpr)++;
1318                         }
1319
1320                         /*
1321                          * At this point, we have an even register
1322                          * so we assign that and move along.
1323                          */
1324                         ainfo->reg = *fpr;
1325                         *fpr += 2;
1326                 } else if (*float_spare >= 0) {
1327                         /*
1328                          * We're passing a single-precision value
1329                          * and it looks like a spare single-
1330                          * precision register is available. Let's
1331                          * use it.
1332                          */
1333
1334                         ainfo->reg = *float_spare;
1335                         *float_spare = -1;
1336                 } else {
1337                         /*
1338                          * If we hit this branch, we're passing a
1339                          * single-precision value and we can simply
1340                          * use the next available register.
1341                          */
1342
1343                         ainfo->reg = *fpr;
1344                         (*fpr)++;
1345                 }
1346         } else {
1347                 /*
1348                  * We've exhausted available floating point
1349                  * regs, so pass the rest on the stack.
1350                  */
1351
1352                 if (is_double) {
1353                         *stack_size += 7;
1354                         *stack_size &= ~7;
1355                 }
1356
1357                 ainfo->offset = *stack_size;
1358                 ainfo->reg = ARMREG_SP;
1359                 ainfo->storage = RegTypeBase;
1360
1361                 *stack_size += 8;
1362         }
1363 }
1364
1365 static CallInfo*
1366 get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSignature *sig)
1367 {
1368         guint i, gr, fpr, pstart;
1369         gint float_spare;
1370         int n = sig->hasthis + sig->param_count;
1371         MonoType *simpletype;
1372         guint32 stack_size = 0;
1373         CallInfo *cinfo;
1374         gboolean is_pinvoke = sig->pinvoke;
1375         MonoType *t;
1376
1377         if (mp)
1378                 cinfo = mono_mempool_alloc0 (mp, sizeof (CallInfo) + (sizeof (ArgInfo) * n));
1379         else
1380                 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
1381
1382         cinfo->nargs = n;
1383         gr = ARMREG_R0;
1384         fpr = ARM_VFP_F0;
1385         float_spare = -1;
1386
1387         t = mini_type_get_underlying_type (gsctx, sig->ret);
1388         if (MONO_TYPE_ISSTRUCT (t)) {
1389                 guint32 align;
1390
1391                 if (is_pinvoke && mono_class_native_size (mono_class_from_mono_type (t), &align) <= sizeof (gpointer)) {
1392                         cinfo->ret.storage = RegTypeStructByVal;
1393                 } else {
1394                         cinfo->vtype_retaddr = TRUE;
1395                 }
1396         } else if (!(t->type == MONO_TYPE_GENERICINST && !mono_type_generic_inst_is_valuetype (t)) && mini_is_gsharedvt_type_gsctx (gsctx, t)) {
1397                 cinfo->vtype_retaddr = TRUE;
1398         }
1399
1400         pstart = 0;
1401         n = 0;
1402         /*
1403          * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
1404          * the first argument, allowing 'this' to be always passed in the first arg reg.
1405          * Also do this if the first argument is a reference type, since virtual calls
1406          * are sometimes made using calli without sig->hasthis set, like in the delegate
1407          * invoke wrappers.
1408          */
1409         if (cinfo->vtype_retaddr && !is_pinvoke && (sig->hasthis || (sig->param_count > 0 && MONO_TYPE_IS_REFERENCE (mini_type_get_underlying_type (gsctx, sig->params [0]))))) {
1410                 if (sig->hasthis) {
1411                         add_general (&gr, &stack_size, cinfo->args + 0, TRUE);
1412                 } else {
1413                         add_general (&gr, &stack_size, &cinfo->args [sig->hasthis + 0], TRUE);
1414                         pstart = 1;
1415                 }
1416                 n ++;
1417                 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
1418                 cinfo->vret_arg_index = 1;
1419         } else {
1420                 /* this */
1421                 if (sig->hasthis) {
1422                         add_general (&gr, &stack_size, cinfo->args + 0, TRUE);
1423                         n ++;
1424                 }
1425
1426                 if (cinfo->vtype_retaddr)
1427                         add_general (&gr, &stack_size, &cinfo->ret, TRUE);
1428         }
1429
1430         DEBUG(printf("params: %d\n", sig->param_count));
1431         for (i = pstart; i < sig->param_count; ++i) {
1432                 ArgInfo *ainfo = &cinfo->args [n];
1433
1434                 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1435                         /* Prevent implicit arguments and sig_cookie from
1436                            being passed in registers */
1437                         gr = ARMREG_R3 + 1;
1438                         fpr = ARM_VFP_F16;
1439                         /* Emit the signature cookie just before the implicit arguments */
1440                         add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
1441                 }
1442                 DEBUG(printf("param %d: ", i));
1443                 if (sig->params [i]->byref) {
1444                         DEBUG(printf("byref\n"));
1445                         add_general (&gr, &stack_size, ainfo, TRUE);
1446                         n++;
1447                         continue;
1448                 }
1449                 simpletype = mini_type_get_underlying_type (gsctx, sig->params [i]);
1450                 switch (simpletype->type) {
1451                 case MONO_TYPE_BOOLEAN:
1452                 case MONO_TYPE_I1:
1453                 case MONO_TYPE_U1:
1454                         cinfo->args [n].size = 1;
1455                         add_general (&gr, &stack_size, ainfo, TRUE);
1456                         n++;
1457                         break;
1458                 case MONO_TYPE_CHAR:
1459                 case MONO_TYPE_I2:
1460                 case MONO_TYPE_U2:
1461                         cinfo->args [n].size = 2;
1462                         add_general (&gr, &stack_size, ainfo, TRUE);
1463                         n++;
1464                         break;
1465                 case MONO_TYPE_I4:
1466                 case MONO_TYPE_U4:
1467                         cinfo->args [n].size = 4;
1468                         add_general (&gr, &stack_size, ainfo, TRUE);
1469                         n++;
1470                         break;
1471                 case MONO_TYPE_I:
1472                 case MONO_TYPE_U:
1473                 case MONO_TYPE_PTR:
1474                 case MONO_TYPE_FNPTR:
1475                 case MONO_TYPE_CLASS:
1476                 case MONO_TYPE_OBJECT:
1477                 case MONO_TYPE_STRING:
1478                 case MONO_TYPE_SZARRAY:
1479                 case MONO_TYPE_ARRAY:
1480                         cinfo->args [n].size = sizeof (gpointer);
1481                         add_general (&gr, &stack_size, ainfo, TRUE);
1482                         n++;
1483                         break;
1484                 case MONO_TYPE_GENERICINST:
1485                         if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1486                                 cinfo->args [n].size = sizeof (gpointer);
1487                                 add_general (&gr, &stack_size, ainfo, TRUE);
1488                                 n++;
1489                                 break;
1490                         }
1491                         if (mini_is_gsharedvt_type_gsctx (gsctx, simpletype)) {
1492                                 /* gsharedvt arguments are passed by ref */
1493                                 g_assert (mini_is_gsharedvt_type_gsctx (gsctx, simpletype));
1494                                 add_general (&gr, &stack_size, ainfo, TRUE);
1495                                 switch (ainfo->storage) {
1496                                 case RegTypeGeneral:
1497                                         ainfo->storage = RegTypeGSharedVtInReg;
1498                                         break;
1499                                 case RegTypeBase:
1500                                         ainfo->storage = RegTypeGSharedVtOnStack;
1501                                         break;
1502                                 default:
1503                                         g_assert_not_reached ();
1504                                 }
1505                                 n++;
1506                                 break;
1507                         }
1508                         /* Fall through */
1509                 case MONO_TYPE_TYPEDBYREF:
1510                 case MONO_TYPE_VALUETYPE: {
1511                         gint size;
1512                         int align_size;
1513                         int nwords;
1514                         guint32 align;
1515
1516                         if (simpletype->type == MONO_TYPE_TYPEDBYREF) {
1517                                 size = sizeof (MonoTypedRef);
1518                                 align = sizeof (gpointer);
1519                         } else {
1520                                 MonoClass *klass = mono_class_from_mono_type (sig->params [i]);
1521                                 if (is_pinvoke)
1522                                         size = mono_class_native_size (klass, &align);
1523                                 else
1524                                         size = mini_type_stack_size_full (gsctx, simpletype, &align, FALSE);
1525                         }
1526                         DEBUG(printf ("load %d bytes struct\n", size));
1527                         align_size = size;
1528                         nwords = 0;
1529                         align_size += (sizeof (gpointer) - 1);
1530                         align_size &= ~(sizeof (gpointer) - 1);
1531                         nwords = (align_size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1532                         ainfo->storage = RegTypeStructByVal;
1533                         ainfo->struct_size = size;
1534                         /* FIXME: align stack_size if needed */
1535                         if (eabi_supported) {
1536                                 if (align >= 8 && (gr & 1))
1537                                         gr ++;
1538                         }
1539                         if (gr > ARMREG_R3) {
1540                                 ainfo->size = 0;
1541                                 ainfo->vtsize = nwords;
1542                         } else {
1543                                 int rest = ARMREG_R3 - gr + 1;
1544                                 int n_in_regs = rest >= nwords? nwords: rest;
1545
1546                                 ainfo->size = n_in_regs;
1547                                 ainfo->vtsize = nwords - n_in_regs;
1548                                 ainfo->reg = gr;
1549                                 gr += n_in_regs;
1550                                 nwords -= n_in_regs;
1551                         }
1552                         if (sig->call_convention == MONO_CALL_VARARG)
1553                                 /* This matches the alignment in mono_ArgIterator_IntGetNextArg () */
1554                                 stack_size = ALIGN_TO (stack_size, align);
1555                         ainfo->offset = stack_size;
1556                         /*g_print ("offset for arg %d at %d\n", n, stack_size);*/
1557                         stack_size += nwords * sizeof (gpointer);
1558                         n++;
1559                         break;
1560                 }
1561                 case MONO_TYPE_U8:
1562                 case MONO_TYPE_I8:
1563                         ainfo->size = 8;
1564                         add_general (&gr, &stack_size, ainfo, FALSE);
1565                         n++;
1566                         break;
1567                 case MONO_TYPE_R4:
1568                         ainfo->size = 4;
1569
1570                         if (IS_HARD_FLOAT)
1571                                 add_float (&fpr, &stack_size, ainfo, FALSE, &float_spare);
1572                         else
1573                                 add_general (&gr, &stack_size, ainfo, TRUE);
1574
1575                         n++;
1576                         break;
1577                 case MONO_TYPE_R8:
1578                         ainfo->size = 8;
1579
1580                         if (IS_HARD_FLOAT)
1581                                 add_float (&fpr, &stack_size, ainfo, TRUE, &float_spare);
1582                         else
1583                                 add_general (&gr, &stack_size, ainfo, FALSE);
1584
1585                         n++;
1586                         break;
1587                 case MONO_TYPE_VAR:
1588                 case MONO_TYPE_MVAR:
1589                         /* gsharedvt arguments are passed by ref */
1590                         g_assert (mini_is_gsharedvt_type_gsctx (gsctx, simpletype));
1591                         add_general (&gr, &stack_size, ainfo, TRUE);
1592                         switch (ainfo->storage) {
1593                         case RegTypeGeneral:
1594                                 ainfo->storage = RegTypeGSharedVtInReg;
1595                                 break;
1596                         case RegTypeBase:
1597                                 ainfo->storage = RegTypeGSharedVtOnStack;
1598                                 break;
1599                         default:
1600                                 g_assert_not_reached ();
1601                         }
1602                         n++;
1603                         break;
1604                 default:
1605                         g_error ("Can't trampoline 0x%x", sig->params [i]->type);
1606                 }
1607         }
1608
1609         /* Handle the case where there are no implicit arguments */
1610         if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1611                 /* Prevent implicit arguments and sig_cookie from
1612                    being passed in registers */
1613                 gr = ARMREG_R3 + 1;
1614                 fpr = ARM_VFP_F16;
1615                 /* Emit the signature cookie just before the implicit arguments */
1616                 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
1617         }
1618
1619         {
1620                 simpletype = mini_type_get_underlying_type (gsctx, sig->ret);
1621                 switch (simpletype->type) {
1622                 case MONO_TYPE_BOOLEAN:
1623                 case MONO_TYPE_I1:
1624                 case MONO_TYPE_U1:
1625                 case MONO_TYPE_I2:
1626                 case MONO_TYPE_U2:
1627                 case MONO_TYPE_CHAR:
1628                 case MONO_TYPE_I4:
1629                 case MONO_TYPE_U4:
1630                 case MONO_TYPE_I:
1631                 case MONO_TYPE_U:
1632                 case MONO_TYPE_PTR:
1633                 case MONO_TYPE_FNPTR:
1634                 case MONO_TYPE_CLASS:
1635                 case MONO_TYPE_OBJECT:
1636                 case MONO_TYPE_SZARRAY:
1637                 case MONO_TYPE_ARRAY:
1638                 case MONO_TYPE_STRING:
1639                         cinfo->ret.storage = RegTypeGeneral;
1640                         cinfo->ret.reg = ARMREG_R0;
1641                         break;
1642                 case MONO_TYPE_U8:
1643                 case MONO_TYPE_I8:
1644                         cinfo->ret.storage = RegTypeIRegPair;
1645                         cinfo->ret.reg = ARMREG_R0;
1646                         break;
1647                 case MONO_TYPE_R4:
1648                 case MONO_TYPE_R8:
1649                         cinfo->ret.storage = RegTypeFP;
1650
1651                         if (IS_HARD_FLOAT) {
1652                                 cinfo->ret.reg = ARM_VFP_F0;
1653                         } else {
1654                                 cinfo->ret.reg = ARMREG_R0;
1655                         }
1656
1657                         break;
1658                 case MONO_TYPE_GENERICINST:
1659                         if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1660                                 cinfo->ret.storage = RegTypeGeneral;
1661                                 cinfo->ret.reg = ARMREG_R0;
1662                                 break;
1663                         }
1664                         // FIXME: Only for variable types
1665                         if (mini_is_gsharedvt_type_gsctx (gsctx, simpletype)) {
1666                                 cinfo->ret.storage = RegTypeStructByAddr;
1667                                 g_assert (cinfo->vtype_retaddr);
1668                                 break;
1669                         }
1670                         /* Fall through */
1671                 case MONO_TYPE_VALUETYPE:
1672                 case MONO_TYPE_TYPEDBYREF:
1673                         if (cinfo->ret.storage != RegTypeStructByVal)
1674                                 cinfo->ret.storage = RegTypeStructByAddr;
1675                         break;
1676                 case MONO_TYPE_VAR:
1677                 case MONO_TYPE_MVAR:
1678                         g_assert (mini_is_gsharedvt_type_gsctx (gsctx, simpletype));
1679                         cinfo->ret.storage = RegTypeStructByAddr;
1680                         g_assert (cinfo->vtype_retaddr);
1681                         break;
1682                 case MONO_TYPE_VOID:
1683                         break;
1684                 default:
1685                         g_error ("Can't handle as return value 0x%x", sig->ret->type);
1686                 }
1687         }
1688
1689         /* align stack size to 8 */
1690         DEBUG (printf ("      stack size: %d (%d)\n", (stack_size + 15) & ~15, stack_size));
1691         stack_size = (stack_size + 7) & ~7;
1692
1693         cinfo->stack_usage = stack_size;
1694         return cinfo;
1695 }
1696
1697
1698 gboolean
1699 mono_arch_tail_call_supported (MonoCompile *cfg, MonoMethodSignature *caller_sig, MonoMethodSignature *callee_sig)
1700 {
1701         MonoType *callee_ret;
1702         CallInfo *c1, *c2;
1703         gboolean res;
1704
1705         if (cfg->compile_aot && !cfg->full_aot)
1706                 /* OP_TAILCALL doesn't work with AOT */
1707                 return FALSE;
1708
1709         c1 = get_call_info (NULL, NULL, caller_sig);
1710         c2 = get_call_info (NULL, NULL, callee_sig);
1711
1712         /*
1713          * Tail calls with more callee stack usage than the caller cannot be supported, since
1714          * the extra stack space would be left on the stack after the tail call.
1715          */
1716         res = c1->stack_usage >= c2->stack_usage;
1717         callee_ret = mini_replace_type (callee_sig->ret);
1718         if (callee_ret && MONO_TYPE_ISSTRUCT (callee_ret) && c2->ret.storage != RegTypeStructByVal)
1719                 /* An address on the callee's stack is passed as the first argument */
1720                 res = FALSE;
1721
1722         if (c2->stack_usage > 16 * 4)
1723                 res = FALSE;
1724
1725         g_free (c1);
1726         g_free (c2);
1727
1728         return res;
1729 }
1730
1731 #ifndef DISABLE_JIT
1732
1733 static gboolean
1734 debug_omit_fp (void)
1735 {
1736 #if 0
1737         return mono_debug_count ();
1738 #else
1739         return TRUE;
1740 #endif
1741 }
1742
1743 /**
1744  * mono_arch_compute_omit_fp:
1745  *
1746  *   Determine whenever the frame pointer can be eliminated.
1747  */
1748 static void
1749 mono_arch_compute_omit_fp (MonoCompile *cfg)
1750 {
1751         MonoMethodSignature *sig;
1752         MonoMethodHeader *header;
1753         int i, locals_size;
1754         CallInfo *cinfo;
1755
1756         if (cfg->arch.omit_fp_computed)
1757                 return;
1758
1759         header = cfg->header;
1760
1761         sig = mono_method_signature (cfg->method);
1762
1763         if (!cfg->arch.cinfo)
1764                 cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
1765         cinfo = cfg->arch.cinfo;
1766
1767         /*
1768          * FIXME: Remove some of the restrictions.
1769          */
1770         cfg->arch.omit_fp = TRUE;
1771         cfg->arch.omit_fp_computed = TRUE;
1772
1773         if (cfg->disable_omit_fp)
1774                 cfg->arch.omit_fp = FALSE;
1775         if (!debug_omit_fp ())
1776                 cfg->arch.omit_fp = FALSE;
1777         /*
1778         if (cfg->method->save_lmf)
1779                 cfg->arch.omit_fp = FALSE;
1780         */
1781         if (cfg->flags & MONO_CFG_HAS_ALLOCA)
1782                 cfg->arch.omit_fp = FALSE;
1783         if (header->num_clauses)
1784                 cfg->arch.omit_fp = FALSE;
1785         if (cfg->param_area)
1786                 cfg->arch.omit_fp = FALSE;
1787         if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
1788                 cfg->arch.omit_fp = FALSE;
1789         if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
1790                 (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE))
1791                 cfg->arch.omit_fp = FALSE;
1792         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1793                 ArgInfo *ainfo = &cinfo->args [i];
1794
1795                 if (ainfo->storage == RegTypeBase || ainfo->storage == RegTypeBaseGen || ainfo->storage == RegTypeStructByVal) {
1796                         /* 
1797                          * The stack offset can only be determined when the frame
1798                          * size is known.
1799                          */
1800                         cfg->arch.omit_fp = FALSE;
1801                 }
1802         }
1803
1804         locals_size = 0;
1805         for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
1806                 MonoInst *ins = cfg->varinfo [i];
1807                 int ialign;
1808
1809                 locals_size += mono_type_size (ins->inst_vtype, &ialign);
1810         }
1811 }
1812
1813 /*
1814  * Set var information according to the calling convention. arm version.
1815  * The locals var stuff should most likely be split in another method.
1816  */
1817 void
1818 mono_arch_allocate_vars (MonoCompile *cfg)
1819 {
1820         MonoMethodSignature *sig;
1821         MonoMethodHeader *header;
1822         MonoInst *ins;
1823         MonoType *sig_ret;
1824         int i, offset, size, align, curinst;
1825         CallInfo *cinfo;
1826         guint32 ualign;
1827
1828         sig = mono_method_signature (cfg->method);
1829
1830         if (!cfg->arch.cinfo)
1831                 cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
1832         cinfo = cfg->arch.cinfo;
1833         sig_ret = mini_replace_type (sig->ret);
1834
1835         mono_arch_compute_omit_fp (cfg);
1836
1837         if (cfg->arch.omit_fp)
1838                 cfg->frame_reg = ARMREG_SP;
1839         else
1840                 cfg->frame_reg = ARMREG_FP;
1841
1842         cfg->flags |= MONO_CFG_HAS_SPILLUP;
1843
1844         /* allow room for the vararg method args: void* and long/double */
1845         if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1846                 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1847
1848         header = cfg->header;
1849
1850         /* See mono_arch_get_global_int_regs () */
1851         if (cfg->flags & MONO_CFG_HAS_CALLS)
1852                 cfg->uses_rgctx_reg = TRUE;
1853
1854         if (cfg->frame_reg != ARMREG_SP)
1855                 cfg->used_int_regs |= 1 << cfg->frame_reg;
1856
1857         if (cfg->compile_aot || cfg->uses_rgctx_reg || COMPILE_LLVM (cfg))
1858                 /* V5 is reserved for passing the vtable/rgctx/IMT method */
1859                 cfg->used_int_regs |= (1 << ARMREG_V5);
1860
1861         offset = 0;
1862         curinst = 0;
1863         if (!MONO_TYPE_ISSTRUCT (sig_ret) && !cinfo->vtype_retaddr) {
1864                 if (sig_ret->type != MONO_TYPE_VOID) {
1865                         cfg->ret->opcode = OP_REGVAR;
1866                         cfg->ret->inst_c0 = ARMREG_R0;
1867                 }
1868         }
1869         /* local vars are at a positive offset from the stack pointer */
1870         /* 
1871          * also note that if the function uses alloca, we use FP
1872          * to point at the local variables.
1873          */
1874         offset = 0; /* linkage area */
1875         /* align the offset to 16 bytes: not sure this is needed here  */
1876         //offset += 8 - 1;
1877         //offset &= ~(8 - 1);
1878
1879         /* add parameter area size for called functions */
1880         offset += cfg->param_area;
1881         offset += 8 - 1;
1882         offset &= ~(8 - 1);
1883         if (cfg->flags & MONO_CFG_HAS_FPOUT)
1884                 offset += 8;
1885
1886         /* allow room to save the return value */
1887         if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1888                 offset += 8;
1889
1890         /* the MonoLMF structure is stored just below the stack pointer */
1891         if (cinfo->ret.storage == RegTypeStructByVal) {
1892                 cfg->ret->opcode = OP_REGOFFSET;
1893                 cfg->ret->inst_basereg = cfg->frame_reg;
1894                 offset += sizeof (gpointer) - 1;
1895                 offset &= ~(sizeof (gpointer) - 1);
1896                 cfg->ret->inst_offset = - offset;
1897                 offset += sizeof(gpointer);
1898         } else if (cinfo->vtype_retaddr) {
1899                 ins = cfg->vret_addr;
1900                 offset += sizeof(gpointer) - 1;
1901                 offset &= ~(sizeof(gpointer) - 1);
1902                 ins->inst_offset = offset;
1903                 ins->opcode = OP_REGOFFSET;
1904                 ins->inst_basereg = cfg->frame_reg;
1905                 if (G_UNLIKELY (cfg->verbose_level > 1)) {
1906                         printf ("vret_addr =");
1907                         mono_print_ins (cfg->vret_addr);
1908                 }
1909                 offset += sizeof(gpointer);
1910         }
1911
1912         /* Allocate these first so they have a small offset, OP_SEQ_POINT depends on this */
1913         if (cfg->arch.seq_point_info_var) {
1914                 MonoInst *ins;
1915
1916                 ins = cfg->arch.seq_point_info_var;
1917
1918                 size = 4;
1919                 align = 4;
1920                 offset += align - 1;
1921                 offset &= ~(align - 1);
1922                 ins->opcode = OP_REGOFFSET;
1923                 ins->inst_basereg = cfg->frame_reg;
1924                 ins->inst_offset = offset;
1925                 offset += size;
1926
1927                 ins = cfg->arch.ss_trigger_page_var;
1928                 size = 4;
1929                 align = 4;
1930                 offset += align - 1;
1931                 offset &= ~(align - 1);
1932                 ins->opcode = OP_REGOFFSET;
1933                 ins->inst_basereg = cfg->frame_reg;
1934                 ins->inst_offset = offset;
1935                 offset += size;
1936         }
1937
1938         if (cfg->arch.seq_point_read_var) {
1939                 MonoInst *ins;
1940
1941                 ins = cfg->arch.seq_point_read_var;
1942
1943                 size = 4;
1944                 align = 4;
1945                 offset += align - 1;
1946                 offset &= ~(align - 1);
1947                 ins->opcode = OP_REGOFFSET;
1948                 ins->inst_basereg = cfg->frame_reg;
1949                 ins->inst_offset = offset;
1950                 offset += size;
1951
1952                 ins = cfg->arch.seq_point_ss_method_var;
1953                 size = 4;
1954                 align = 4;
1955                 offset += align - 1;
1956                 offset &= ~(align - 1);
1957                 ins->opcode = OP_REGOFFSET;
1958                 ins->inst_basereg = cfg->frame_reg;
1959                 ins->inst_offset = offset;
1960                 offset += size;
1961
1962                 ins = cfg->arch.seq_point_bp_method_var;
1963                 size = 4;
1964                 align = 4;
1965                 offset += align - 1;
1966                 offset &= ~(align - 1);
1967                 ins->opcode = OP_REGOFFSET;
1968                 ins->inst_basereg = cfg->frame_reg;
1969                 ins->inst_offset = offset;
1970                 offset += size;
1971         }
1972
1973         if (cfg->has_atomic_exchange_i4 || cfg->has_atomic_cas_i4 || cfg->has_atomic_add_i4) {
1974                 /* Allocate a temporary used by the atomic ops */
1975                 size = 4;
1976                 align = 4;
1977
1978                 /* Allocate a local slot to hold the sig cookie address */
1979                 offset += align - 1;
1980                 offset &= ~(align - 1);
1981                 cfg->arch.atomic_tmp_offset = offset;
1982                 offset += size;
1983         } else {
1984                 cfg->arch.atomic_tmp_offset = -1;
1985         }
1986
1987         cfg->locals_min_stack_offset = offset;
1988
1989         curinst = cfg->locals_start;
1990         for (i = curinst; i < cfg->num_varinfo; ++i) {
1991                 MonoType *t;
1992
1993                 ins = cfg->varinfo [i];
1994                 if ((ins->flags & MONO_INST_IS_DEAD) || ins->opcode == OP_REGVAR || ins->opcode == OP_REGOFFSET)
1995                         continue;
1996
1997                 t = ins->inst_vtype;
1998                 if (cfg->gsharedvt && mini_is_gsharedvt_variable_type (cfg, t))
1999                         continue;
2000
2001                 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
2002                 * pinvoke wrappers when they call functions returning structure */
2003                 if (ins->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (t) && t->type != MONO_TYPE_TYPEDBYREF) {
2004                         size = mono_class_native_size (mono_class_from_mono_type (t), &ualign);
2005                         align = ualign;
2006                 }
2007                 else
2008                         size = mono_type_size (t, &align);
2009
2010                 /* FIXME: if a structure is misaligned, our memcpy doesn't work,
2011                  * since it loads/stores misaligned words, which don't do the right thing.
2012                  */
2013                 if (align < 4 && size >= 4)
2014                         align = 4;
2015                 if (ALIGN_TO (offset, align) > ALIGN_TO (offset, 4))
2016                         mini_gc_set_slot_type_from_fp (cfg, ALIGN_TO (offset, 4), SLOT_NOREF);
2017                 offset += align - 1;
2018                 offset &= ~(align - 1);
2019                 ins->opcode = OP_REGOFFSET;
2020                 ins->inst_offset = offset;
2021                 ins->inst_basereg = cfg->frame_reg;
2022                 offset += size;
2023                 //g_print ("allocating local %d to %d\n", i, inst->inst_offset);
2024         }
2025
2026         cfg->locals_max_stack_offset = offset;
2027
2028         curinst = 0;
2029         if (sig->hasthis) {
2030                 ins = cfg->args [curinst];
2031                 if (ins->opcode != OP_REGVAR) {
2032                         ins->opcode = OP_REGOFFSET;
2033                         ins->inst_basereg = cfg->frame_reg;
2034                         offset += sizeof (gpointer) - 1;
2035                         offset &= ~(sizeof (gpointer) - 1);
2036                         ins->inst_offset = offset;
2037                         offset += sizeof (gpointer);
2038                 }
2039                 curinst++;
2040         }
2041
2042         if (sig->call_convention == MONO_CALL_VARARG) {
2043                 size = 4;
2044                 align = 4;
2045
2046                 /* Allocate a local slot to hold the sig cookie address */
2047                 offset += align - 1;
2048                 offset &= ~(align - 1);
2049                 cfg->sig_cookie = offset;
2050                 offset += size;
2051         }                       
2052
2053         for (i = 0; i < sig->param_count; ++i) {
2054                 ins = cfg->args [curinst];
2055
2056                 if (ins->opcode != OP_REGVAR) {
2057                         ins->opcode = OP_REGOFFSET;
2058                         ins->inst_basereg = cfg->frame_reg;
2059                         size = mini_type_stack_size_full (cfg->generic_sharing_context, sig->params [i], &ualign, sig->pinvoke);
2060                         align = ualign;
2061                         /* FIXME: if a structure is misaligned, our memcpy doesn't work,
2062                          * since it loads/stores misaligned words, which don't do the right thing.
2063                          */
2064                         if (align < 4 && size >= 4)
2065                                 align = 4;
2066                         /* The code in the prolog () stores words when storing vtypes received in a register */
2067                         if (MONO_TYPE_ISSTRUCT (sig->params [i]))
2068                                 align = 4;
2069                         if (ALIGN_TO (offset, align) > ALIGN_TO (offset, 4))
2070                                 mini_gc_set_slot_type_from_fp (cfg, ALIGN_TO (offset, 4), SLOT_NOREF);
2071                         offset += align - 1;
2072                         offset &= ~(align - 1);
2073                         ins->inst_offset = offset;
2074                         offset += size;
2075                 }
2076                 curinst++;
2077         }
2078
2079         /* align the offset to 8 bytes */
2080         if (ALIGN_TO (offset, 8) > ALIGN_TO (offset, 4))
2081                 mini_gc_set_slot_type_from_fp (cfg, ALIGN_TO (offset, 4), SLOT_NOREF);
2082         offset += 8 - 1;
2083         offset &= ~(8 - 1);
2084
2085         /* change sign? */
2086         cfg->stack_offset = offset;
2087 }
2088
2089 void
2090 mono_arch_create_vars (MonoCompile *cfg)
2091 {
2092         MonoMethodSignature *sig;
2093         CallInfo *cinfo;
2094         int i;
2095
2096         sig = mono_method_signature (cfg->method);
2097
2098         if (!cfg->arch.cinfo)
2099                 cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
2100         cinfo = cfg->arch.cinfo;
2101
2102         if (IS_HARD_FLOAT) {
2103                 for (i = 0; i < 2; i++) {
2104                         MonoInst *inst = mono_compile_create_var (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL);
2105                         inst->flags |= MONO_INST_VOLATILE;
2106
2107                         cfg->arch.vfp_scratch_slots [i] = (gpointer) inst;
2108                 }
2109         }
2110
2111         if (cinfo->ret.storage == RegTypeStructByVal)
2112                 cfg->ret_var_is_local = TRUE;
2113
2114         if (cinfo->vtype_retaddr) {
2115                 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
2116                 if (G_UNLIKELY (cfg->verbose_level > 1)) {
2117                         printf ("vret_addr = ");
2118                         mono_print_ins (cfg->vret_addr);
2119                 }
2120         }
2121
2122         if (cfg->gen_seq_points) {
2123                 if (cfg->soft_breakpoints) {
2124                         MonoInst *ins = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2125                         ins->flags |= MONO_INST_VOLATILE;
2126                         cfg->arch.seq_point_read_var = ins;
2127
2128                         ins = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2129                         ins->flags |= MONO_INST_VOLATILE;
2130                         cfg->arch.seq_point_ss_method_var = ins;
2131
2132                         ins = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2133                         ins->flags |= MONO_INST_VOLATILE;
2134                         cfg->arch.seq_point_bp_method_var = ins;
2135
2136                         g_assert (!cfg->compile_aot);
2137                 } else if (cfg->compile_aot) {
2138                         MonoInst *ins = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2139                         ins->flags |= MONO_INST_VOLATILE;
2140                         cfg->arch.seq_point_info_var = ins;
2141
2142                         /* Allocate a separate variable for this to save 1 load per seq point */
2143                         ins = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2144                         ins->flags |= MONO_INST_VOLATILE;
2145                         cfg->arch.ss_trigger_page_var = ins;
2146                 }
2147         }
2148 }
2149
2150 static void
2151 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
2152 {
2153         MonoMethodSignature *tmp_sig;
2154         int sig_reg;
2155
2156         if (call->tail_call)
2157                 NOT_IMPLEMENTED;
2158
2159         g_assert (cinfo->sig_cookie.storage == RegTypeBase);
2160                         
2161         /*
2162          * mono_ArgIterator_Setup assumes the signature cookie is 
2163          * passed first and all the arguments which were before it are
2164          * passed on the stack after the signature. So compensate by 
2165          * passing a different signature.
2166          */
2167         tmp_sig = mono_metadata_signature_dup (call->signature);
2168         tmp_sig->param_count -= call->signature->sentinelpos;
2169         tmp_sig->sentinelpos = 0;
2170         memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
2171
2172         sig_reg = mono_alloc_ireg (cfg);
2173         MONO_EMIT_NEW_SIGNATURECONST (cfg, sig_reg, tmp_sig);
2174
2175         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ARMREG_SP, cinfo->sig_cookie.offset, sig_reg);
2176 }
2177
2178 #ifdef ENABLE_LLVM
2179 LLVMCallInfo*
2180 mono_arch_get_llvm_call_info (MonoCompile *cfg, MonoMethodSignature *sig)
2181 {
2182         int i, n;
2183         CallInfo *cinfo;
2184         ArgInfo *ainfo;
2185         LLVMCallInfo *linfo;
2186
2187         n = sig->param_count + sig->hasthis;
2188
2189         cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
2190
2191         linfo = mono_mempool_alloc0 (cfg->mempool, sizeof (LLVMCallInfo) + (sizeof (LLVMArgInfo) * n));
2192
2193         /*
2194          * LLVM always uses the native ABI while we use our own ABI, the
2195          * only difference is the handling of vtypes:
2196          * - we only pass/receive them in registers in some cases, and only 
2197          *   in 1 or 2 integer registers.
2198          */
2199         if (cinfo->vtype_retaddr) {
2200                 /* Vtype returned using a hidden argument */
2201                 linfo->ret.storage = LLVMArgVtypeRetAddr;
2202                 linfo->vret_arg_index = cinfo->vret_arg_index;
2203         } else if (cinfo->ret.storage != RegTypeGeneral && cinfo->ret.storage != RegTypeNone && cinfo->ret.storage != RegTypeFP && cinfo->ret.storage != RegTypeIRegPair) {
2204                 cfg->exception_message = g_strdup ("unknown ret conv");
2205                 cfg->disable_llvm = TRUE;
2206                 return linfo;
2207         }
2208
2209         for (i = 0; i < n; ++i) {
2210                 ainfo = cinfo->args + i;
2211
2212                 linfo->args [i].storage = LLVMArgNone;
2213
2214                 switch (ainfo->storage) {
2215                 case RegTypeGeneral:
2216                 case RegTypeIRegPair:
2217                 case RegTypeBase:
2218                         linfo->args [i].storage = LLVMArgInIReg;
2219                         break;
2220                 case RegTypeStructByVal:
2221                         // FIXME: Passing entirely on the stack or split reg/stack
2222                         if (ainfo->vtsize == 0 && ainfo->size <= 2) {
2223                                 linfo->args [i].storage = LLVMArgVtypeInReg;
2224                                 linfo->args [i].pair_storage [0] = LLVMArgInIReg;
2225                                 if (ainfo->size == 2)
2226                                         linfo->args [i].pair_storage [1] = LLVMArgInIReg;
2227                                 else
2228                                         linfo->args [i].pair_storage [1] = LLVMArgNone;
2229                         } else {
2230                                 cfg->exception_message = g_strdup_printf ("vtype-by-val on stack");
2231                                 cfg->disable_llvm = TRUE;
2232                         }
2233                         break;
2234                 default:
2235                         cfg->exception_message = g_strdup_printf ("ainfo->storage (%d)", ainfo->storage);
2236                         cfg->disable_llvm = TRUE;
2237                         break;
2238                 }
2239         }
2240
2241         return linfo;
2242 }
2243 #endif
2244
2245 void
2246 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
2247 {
2248         MonoInst *in, *ins;
2249         MonoMethodSignature *sig;
2250         int i, n;
2251         CallInfo *cinfo;
2252
2253         sig = call->signature;
2254         n = sig->param_count + sig->hasthis;
2255         
2256         cinfo = get_call_info (cfg->generic_sharing_context, NULL, sig);
2257
2258         for (i = 0; i < n; ++i) {
2259                 ArgInfo *ainfo = cinfo->args + i;
2260                 MonoType *t;
2261
2262                 if (i >= sig->hasthis)
2263                         t = sig->params [i - sig->hasthis];
2264                 else
2265                         t = &mono_defaults.int_class->byval_arg;
2266                 t = mini_type_get_underlying_type (cfg->generic_sharing_context, t);
2267
2268                 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
2269                         /* Emit the signature cookie just before the implicit arguments */
2270                         emit_sig_cookie (cfg, call, cinfo);
2271                 }
2272
2273                 in = call->args [i];
2274
2275                 switch (ainfo->storage) {
2276                 case RegTypeGeneral:
2277                 case RegTypeIRegPair:
2278                         if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
2279                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
2280                                 ins->dreg = mono_alloc_ireg (cfg);
2281                                 ins->sreg1 = in->dreg + 1;
2282                                 MONO_ADD_INS (cfg->cbb, ins);
2283                                 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
2284
2285                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
2286                                 ins->dreg = mono_alloc_ireg (cfg);
2287                                 ins->sreg1 = in->dreg + 2;
2288                                 MONO_ADD_INS (cfg->cbb, ins);
2289                                 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + 1, FALSE);
2290                         } else if (!t->byref && ((t->type == MONO_TYPE_R8) || (t->type == MONO_TYPE_R4))) {
2291                                 if (ainfo->size == 4) {
2292                                         if (IS_SOFT_FLOAT) {
2293                                                 /* mono_emit_call_args () have already done the r8->r4 conversion */
2294                                                 /* The converted value is in an int vreg */
2295                                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
2296                                                 ins->dreg = mono_alloc_ireg (cfg);
2297                                                 ins->sreg1 = in->dreg;
2298                                                 MONO_ADD_INS (cfg->cbb, ins);
2299                                                 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
2300                                         } else {
2301                                                 int creg;
2302
2303                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, ARMREG_SP, (cfg->param_area - 8), in->dreg);
2304                                                 creg = mono_alloc_ireg (cfg);
2305                                                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOAD_MEMBASE, creg, ARMREG_SP, (cfg->param_area - 8));
2306                                                 mono_call_inst_add_outarg_reg (cfg, call, creg, ainfo->reg, FALSE);
2307                                         }
2308                                 } else {
2309                                         if (IS_SOFT_FLOAT) {
2310                                                 MONO_INST_NEW (cfg, ins, OP_FGETLOW32);
2311                                                 ins->dreg = mono_alloc_ireg (cfg);
2312                                                 ins->sreg1 = in->dreg;
2313                                                 MONO_ADD_INS (cfg->cbb, ins);
2314                                                 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
2315
2316                                                 MONO_INST_NEW (cfg, ins, OP_FGETHIGH32);
2317                                                 ins->dreg = mono_alloc_ireg (cfg);
2318                                                 ins->sreg1 = in->dreg;
2319                                                 MONO_ADD_INS (cfg->cbb, ins);
2320                                                 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + 1, FALSE);
2321                                         } else {
2322                                                 int creg;
2323
2324                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ARMREG_SP, (cfg->param_area - 8), in->dreg);
2325                                                 creg = mono_alloc_ireg (cfg);
2326                                                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOAD_MEMBASE, creg, ARMREG_SP, (cfg->param_area - 8));
2327                                                 mono_call_inst_add_outarg_reg (cfg, call, creg, ainfo->reg, FALSE);
2328                                                 creg = mono_alloc_ireg (cfg);
2329                                                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOAD_MEMBASE, creg, ARMREG_SP, (cfg->param_area - 8 + 4));
2330                                                 mono_call_inst_add_outarg_reg (cfg, call, creg, ainfo->reg + 1, FALSE);
2331                                         }
2332                                 }
2333                                 cfg->flags |= MONO_CFG_HAS_FPOUT;
2334                         } else {
2335                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
2336                                 ins->dreg = mono_alloc_ireg (cfg);
2337                                 ins->sreg1 = in->dreg;
2338                                 MONO_ADD_INS (cfg->cbb, ins);
2339
2340                                 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
2341                         }
2342                         break;
2343                 case RegTypeStructByAddr:
2344                         NOT_IMPLEMENTED;
2345 #if 0
2346                         /* FIXME: where si the data allocated? */
2347                         arg->backend.reg3 = ainfo->reg;
2348                         call->used_iregs |= 1 << ainfo->reg;
2349                         g_assert_not_reached ();
2350 #endif
2351                         break;
2352                 case RegTypeStructByVal:
2353                 case RegTypeGSharedVtInReg:
2354                 case RegTypeGSharedVtOnStack:
2355                         MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
2356                         ins->opcode = OP_OUTARG_VT;
2357                         ins->sreg1 = in->dreg;
2358                         ins->klass = in->klass;
2359                         ins->inst_p0 = call;
2360                         ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
2361                         memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
2362                         mono_call_inst_add_outarg_vt (cfg, call, ins);
2363                         MONO_ADD_INS (cfg->cbb, ins);
2364                         break;
2365                 case RegTypeBase:
2366                         if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
2367                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, ARMREG_SP, ainfo->offset, in->dreg);
2368                         } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
2369                                 if (t->type == MONO_TYPE_R8) {
2370                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ARMREG_SP, ainfo->offset, in->dreg);
2371                                 } else {
2372                                         if (IS_SOFT_FLOAT)
2373                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, ARMREG_SP, ainfo->offset, in->dreg);
2374                                         else
2375                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, ARMREG_SP, ainfo->offset, in->dreg);
2376                                 }
2377                         } else {
2378                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ARMREG_SP, ainfo->offset, in->dreg);
2379                         }
2380                         break;
2381                 case RegTypeBaseGen:
2382                         if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
2383                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ARMREG_SP, ainfo->offset, (G_BYTE_ORDER == G_BIG_ENDIAN) ? in->dreg + 1 : in->dreg + 2);
2384                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
2385                                 ins->dreg = mono_alloc_ireg (cfg);
2386                                 ins->sreg1 = G_BYTE_ORDER == G_BIG_ENDIAN ? in->dreg + 2 : in->dreg + 1;
2387                                 MONO_ADD_INS (cfg->cbb, ins);
2388                                 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ARMREG_R3, FALSE);
2389                         } else if (!t->byref && (t->type == MONO_TYPE_R8)) {
2390                                 int creg;
2391
2392                                 /* This should work for soft-float as well */
2393
2394                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ARMREG_SP, (cfg->param_area - 8), in->dreg);
2395                                 creg = mono_alloc_ireg (cfg);
2396                                 mono_call_inst_add_outarg_reg (cfg, call, creg, ARMREG_R3, FALSE);
2397                                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOAD_MEMBASE, creg, ARMREG_SP, (cfg->param_area - 8));
2398                                 creg = mono_alloc_ireg (cfg);
2399                                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOAD_MEMBASE, creg, ARMREG_SP, (cfg->param_area - 4));
2400                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ARMREG_SP, ainfo->offset, creg);
2401                                 cfg->flags |= MONO_CFG_HAS_FPOUT;
2402                         } else {
2403                                 g_assert_not_reached ();
2404                         }
2405                         break;
2406                 case RegTypeFP: {
2407                         int fdreg = mono_alloc_freg (cfg);
2408
2409                         if (ainfo->size == 8) {
2410                                 MONO_INST_NEW (cfg, ins, OP_FMOVE);
2411                                 ins->sreg1 = in->dreg;
2412                                 ins->dreg = fdreg;
2413                                 MONO_ADD_INS (cfg->cbb, ins);
2414
2415                                 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, TRUE);
2416                         } else {
2417                                 FloatArgData *fad;
2418
2419                                 /*
2420                                  * Mono's register allocator doesn't speak single-precision registers that
2421                                  * overlap double-precision registers (i.e. armhf). So we have to work around
2422                                  * the register allocator and load the value from memory manually.
2423                                  *
2424                                  * So we create a variable for the float argument and an instruction to store
2425                                  * the argument into the variable. We then store the list of these arguments
2426                                  * in cfg->float_args. This list is then used by emit_float_args later to
2427                                  * pass the arguments in the various call opcodes.
2428                                  *
2429                                  * This is not very nice, and we should really try to fix the allocator.
2430                                  */
2431
2432                                 MonoInst *float_arg = mono_compile_create_var (cfg, &mono_defaults.single_class->byval_arg, OP_LOCAL);
2433
2434                                 /* Make sure the instruction isn't seen as pointless and removed.
2435                                  */
2436                                 float_arg->flags |= MONO_INST_VOLATILE;
2437
2438                                 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, float_arg->dreg, in->dreg);
2439
2440                                 /* We use the dreg to look up the instruction later. The hreg is used to
2441                                  * emit the instruction that loads the value into the FP reg.
2442                                  */
2443                                 fad = mono_mempool_alloc0 (cfg->mempool, sizeof (FloatArgData));
2444                                 fad->vreg = float_arg->dreg;
2445                                 fad->hreg = ainfo->reg;
2446
2447                                 call->float_args = g_slist_append_mempool (cfg->mempool, call->float_args, fad);
2448                         }
2449
2450                         call->used_iregs |= 1 << ainfo->reg;
2451                         cfg->flags |= MONO_CFG_HAS_FPOUT;
2452                         break;
2453                 }
2454                 default:
2455                         g_assert_not_reached ();
2456                 }
2457         }
2458
2459         /* Handle the case where there are no implicit arguments */
2460         if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
2461                 emit_sig_cookie (cfg, call, cinfo);
2462
2463         if (cinfo->ret.storage == RegTypeStructByVal) {
2464                 /* The JIT will transform this into a normal call */
2465                 call->vret_in_reg = TRUE;
2466         } else if (cinfo->vtype_retaddr) {
2467                 MonoInst *vtarg;
2468                 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
2469                 vtarg->sreg1 = call->vret_var->dreg;
2470                 vtarg->dreg = mono_alloc_preg (cfg);
2471                 MONO_ADD_INS (cfg->cbb, vtarg);
2472
2473                 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->ret.reg, FALSE);
2474         }
2475
2476         call->stack_usage = cinfo->stack_usage;
2477
2478         g_free (cinfo);
2479 }
2480
2481 void
2482 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
2483 {
2484         MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
2485         ArgInfo *ainfo = ins->inst_p1;
2486         int ovf_size = ainfo->vtsize;
2487         int doffset = ainfo->offset;
2488         int struct_size = ainfo->struct_size;
2489         int i, soffset, dreg, tmpreg;
2490
2491         if (ainfo->storage == RegTypeGSharedVtInReg) {
2492                 /* Pass by addr */
2493                 mono_call_inst_add_outarg_reg (cfg, call, src->dreg, ainfo->reg, FALSE);
2494                 return;
2495         }
2496         if (ainfo->storage == RegTypeGSharedVtOnStack) {
2497                 /* Pass by addr on stack */
2498                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ARMREG_SP, ainfo->offset, src->dreg);
2499                 return;
2500         }
2501
2502         soffset = 0;
2503         for (i = 0; i < ainfo->size; ++i) {
2504                 dreg = mono_alloc_ireg (cfg);
2505                 switch (struct_size) {
2506                 case 1:
2507                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, dreg, src->dreg, soffset);
2508                         break;
2509                 case 2:
2510                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, dreg, src->dreg, soffset);
2511                         break;
2512                 case 3:
2513                         tmpreg = mono_alloc_ireg (cfg);
2514                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, dreg, src->dreg, soffset);
2515                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, tmpreg, src->dreg, soffset + 1);
2516                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, tmpreg, tmpreg, 8);
2517                         MONO_EMIT_NEW_BIALU (cfg, OP_IOR, dreg, dreg, tmpreg);
2518                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, tmpreg, src->dreg, soffset + 2);
2519                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, tmpreg, tmpreg, 16);
2520                         MONO_EMIT_NEW_BIALU (cfg, OP_IOR, dreg, dreg, tmpreg);
2521                         break;
2522                 default:
2523                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
2524                         break;
2525                 }
2526                 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
2527                 soffset += sizeof (gpointer);
2528                 struct_size -= sizeof (gpointer);
2529         }
2530         //g_print ("vt size: %d at R%d + %d\n", doffset, vt->inst_basereg, vt->inst_offset);
2531         if (ovf_size != 0)
2532                 mini_emit_memcpy (cfg, ARMREG_SP, doffset, src->dreg, soffset, MIN (ovf_size * sizeof (gpointer), struct_size), struct_size < 4 ? 1 : 4);
2533 }
2534
2535 void
2536 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
2537 {
2538         MonoType *ret = mini_type_get_underlying_type (cfg->generic_sharing_context, mono_method_signature (method)->ret);
2539
2540         if (!ret->byref) {
2541                 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
2542                         MonoInst *ins;
2543
2544                         if (COMPILE_LLVM (cfg)) {
2545                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
2546                         } else {
2547                                 MONO_INST_NEW (cfg, ins, OP_SETLRET);
2548                                 ins->sreg1 = val->dreg + 1;
2549                                 ins->sreg2 = val->dreg + 2;
2550                                 MONO_ADD_INS (cfg->cbb, ins);
2551                         }
2552                         return;
2553                 }
2554                 switch (arm_fpu) {
2555                 case MONO_ARM_FPU_NONE:
2556                         if (ret->type == MONO_TYPE_R8) {
2557                                 MonoInst *ins;
2558
2559                                 MONO_INST_NEW (cfg, ins, OP_SETFRET);
2560                                 ins->dreg = cfg->ret->dreg;
2561                                 ins->sreg1 = val->dreg;
2562                                 MONO_ADD_INS (cfg->cbb, ins);
2563                                 return;
2564                         }
2565                         if (ret->type == MONO_TYPE_R4) {
2566                                 /* Already converted to an int in method_to_ir () */
2567                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
2568                                 return;
2569                         }
2570                         break;
2571                 case MONO_ARM_FPU_VFP:
2572                 case MONO_ARM_FPU_VFP_HARD:
2573                         if (ret->type == MONO_TYPE_R8 || ret->type == MONO_TYPE_R4) {
2574                                 MonoInst *ins;
2575
2576                                 MONO_INST_NEW (cfg, ins, OP_SETFRET);
2577                                 ins->dreg = cfg->ret->dreg;
2578                                 ins->sreg1 = val->dreg;
2579                                 MONO_ADD_INS (cfg->cbb, ins);
2580                                 return;
2581                         }
2582                         break;
2583                 default:
2584                         g_assert_not_reached ();
2585                 }
2586         }
2587
2588         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
2589 }
2590
2591 #endif /* #ifndef DISABLE_JIT */
2592
2593 gboolean 
2594 mono_arch_is_inst_imm (gint64 imm)
2595 {
2596         return TRUE;
2597 }
2598
2599 typedef struct {
2600         MonoMethodSignature *sig;
2601         CallInfo *cinfo;
2602         MonoType *rtype;
2603         MonoType **param_types;
2604 } ArchDynCallInfo;
2605
2606 static gboolean
2607 dyn_call_supported (CallInfo *cinfo, MonoMethodSignature *sig)
2608 {
2609         int i;
2610
2611         if (sig->hasthis + sig->param_count > PARAM_REGS + DYN_CALL_STACK_ARGS)
2612                 return FALSE;
2613
2614         switch (cinfo->ret.storage) {
2615         case RegTypeNone:
2616         case RegTypeGeneral:
2617         case RegTypeIRegPair:
2618         case RegTypeStructByAddr:
2619                 break;
2620         case RegTypeFP:
2621                 if (IS_VFP)
2622                         break;
2623                 else
2624                         return FALSE;
2625         default:
2626                 return FALSE;
2627         }
2628
2629         for (i = 0; i < cinfo->nargs; ++i) {
2630                 ArgInfo *ainfo = &cinfo->args [i];
2631                 int last_slot;
2632
2633                 switch (ainfo->storage) {
2634                 case RegTypeGeneral:
2635                         break;
2636                 case RegTypeIRegPair:
2637                         break;
2638                 case RegTypeBase:
2639                         if (ainfo->offset >= (DYN_CALL_STACK_ARGS * sizeof (gpointer)))
2640                                 return FALSE;
2641                         break;
2642                 case RegTypeStructByVal:
2643                         if (ainfo->size == 0)
2644                                 last_slot = PARAM_REGS + (ainfo->offset / 4) + ainfo->vtsize;
2645                         else
2646                                 last_slot = ainfo->reg + ainfo->size + ainfo->vtsize;
2647                         if (last_slot >= PARAM_REGS + DYN_CALL_STACK_ARGS)
2648                                 return FALSE;
2649                         break;
2650                 default:
2651                         return FALSE;
2652                 }
2653         }
2654
2655         // FIXME: Can't use cinfo only as it doesn't contain info about I8/float */
2656         for (i = 0; i < sig->param_count; ++i) {
2657                 MonoType *t = sig->params [i];
2658
2659                 if (t->byref)
2660                         continue;
2661
2662                 switch (t->type) {
2663                 case MONO_TYPE_R4:
2664                 case MONO_TYPE_R8:
2665                         if (IS_SOFT_FLOAT)
2666                                 return FALSE;
2667                         else
2668                                 break;
2669                         /*
2670                 case MONO_TYPE_I8:
2671                 case MONO_TYPE_U8:
2672                         return FALSE;
2673                         */
2674                 default:
2675                         break;
2676                 }
2677         }
2678
2679         return TRUE;
2680 }
2681
2682 MonoDynCallInfo*
2683 mono_arch_dyn_call_prepare (MonoMethodSignature *sig)
2684 {
2685         ArchDynCallInfo *info;
2686         CallInfo *cinfo;
2687         int i;
2688
2689         cinfo = get_call_info (NULL, NULL, sig);
2690
2691         if (!dyn_call_supported (cinfo, sig)) {
2692                 g_free (cinfo);
2693                 return NULL;
2694         }
2695
2696         info = g_new0 (ArchDynCallInfo, 1);
2697         // FIXME: Preprocess the info to speed up start_dyn_call ()
2698         info->sig = sig;
2699         info->cinfo = cinfo;
2700         info->rtype = mini_replace_type (sig->ret);
2701         info->param_types = g_new0 (MonoType*, sig->param_count);
2702         for (i = 0; i < sig->param_count; ++i)
2703                 info->param_types [i] = mini_replace_type (sig->params [i]);
2704         
2705         return (MonoDynCallInfo*)info;
2706 }
2707
2708 void
2709 mono_arch_dyn_call_free (MonoDynCallInfo *info)
2710 {
2711         ArchDynCallInfo *ainfo = (ArchDynCallInfo*)info;
2712
2713         g_free (ainfo->cinfo);
2714         g_free (ainfo);
2715 }
2716
2717 void
2718 mono_arch_start_dyn_call (MonoDynCallInfo *info, gpointer **args, guint8 *ret, guint8 *buf, int buf_len)
2719 {
2720         ArchDynCallInfo *dinfo = (ArchDynCallInfo*)info;
2721         DynCallArgs *p = (DynCallArgs*)buf;
2722         int arg_index, greg, i, j, pindex;
2723         MonoMethodSignature *sig = dinfo->sig;
2724
2725         g_assert (buf_len >= sizeof (DynCallArgs));
2726
2727         p->res = 0;
2728         p->ret = ret;
2729
2730         arg_index = 0;
2731         greg = 0;
2732         pindex = 0;
2733
2734         if (sig->hasthis || dinfo->cinfo->vret_arg_index == 1) {
2735                 p->regs [greg ++] = (mgreg_t)*(args [arg_index ++]);
2736                 if (!sig->hasthis)
2737                         pindex = 1;
2738         }
2739
2740         if (dinfo->cinfo->vtype_retaddr)
2741                 p->regs [greg ++] = (mgreg_t)ret;
2742
2743         for (i = pindex; i < sig->param_count; i++) {
2744                 MonoType *t = dinfo->param_types [i];
2745                 gpointer *arg = args [arg_index ++];
2746                 ArgInfo *ainfo = &dinfo->cinfo->args [i + sig->hasthis];
2747                 int slot = -1;
2748
2749                 if (ainfo->storage == RegTypeGeneral || ainfo->storage == RegTypeIRegPair || ainfo->storage == RegTypeStructByVal)
2750                         slot = ainfo->reg;
2751                 else if (ainfo->storage == RegTypeBase)
2752                         slot = PARAM_REGS + (ainfo->offset / 4);
2753                 else
2754                         g_assert_not_reached ();
2755
2756                 if (t->byref) {
2757                         p->regs [slot] = (mgreg_t)*arg;
2758                         continue;
2759                 }
2760
2761                 switch (t->type) {
2762                 case MONO_TYPE_STRING:
2763                 case MONO_TYPE_CLASS:  
2764                 case MONO_TYPE_ARRAY:
2765                 case MONO_TYPE_SZARRAY:
2766                 case MONO_TYPE_OBJECT:
2767                 case MONO_TYPE_PTR:
2768                 case MONO_TYPE_I:
2769                 case MONO_TYPE_U:
2770                         p->regs [slot] = (mgreg_t)*arg;
2771                         break;
2772                 case MONO_TYPE_BOOLEAN:
2773                 case MONO_TYPE_U1:
2774                         p->regs [slot] = *(guint8*)arg;
2775                         break;
2776                 case MONO_TYPE_I1:
2777                         p->regs [slot] = *(gint8*)arg;
2778                         break;
2779                 case MONO_TYPE_I2:
2780                         p->regs [slot] = *(gint16*)arg;
2781                         break;
2782                 case MONO_TYPE_U2:
2783                 case MONO_TYPE_CHAR:
2784                         p->regs [slot] = *(guint16*)arg;
2785                         break;
2786                 case MONO_TYPE_I4:
2787                         p->regs [slot] = *(gint32*)arg;
2788                         break;
2789                 case MONO_TYPE_U4:
2790                         p->regs [slot] = *(guint32*)arg;
2791                         break;
2792                 case MONO_TYPE_I8:
2793                 case MONO_TYPE_U8:
2794                         p->regs [slot ++] = (mgreg_t)arg [0];
2795                         p->regs [slot] = (mgreg_t)arg [1];
2796                         break;
2797                 case MONO_TYPE_R4:
2798                         p->regs [slot] = *(mgreg_t*)arg;
2799                         break;
2800                 case MONO_TYPE_R8:
2801                         p->regs [slot ++] = (mgreg_t)arg [0];
2802                         p->regs [slot] = (mgreg_t)arg [1];
2803                         break;
2804                 case MONO_TYPE_GENERICINST:
2805                         if (MONO_TYPE_IS_REFERENCE (t)) {
2806                                 p->regs [slot] = (mgreg_t)*arg;
2807                                 break;
2808                         } else {
2809                                 /* Fall though */
2810                         }
2811                 case MONO_TYPE_VALUETYPE:
2812                         g_assert (ainfo->storage == RegTypeStructByVal);
2813
2814                         if (ainfo->size == 0)
2815                                 slot = PARAM_REGS + (ainfo->offset / 4);
2816                         else
2817                                 slot = ainfo->reg;
2818
2819                         for (j = 0; j < ainfo->size + ainfo->vtsize; ++j)
2820                                 p->regs [slot ++] = ((mgreg_t*)arg) [j];
2821                         break;
2822                 default:
2823                         g_assert_not_reached ();
2824                 }
2825         }
2826 }
2827
2828 void
2829 mono_arch_finish_dyn_call (MonoDynCallInfo *info, guint8 *buf)
2830 {
2831         ArchDynCallInfo *ainfo = (ArchDynCallInfo*)info;
2832         MonoType *ptype = ainfo->rtype;
2833         guint8 *ret = ((DynCallArgs*)buf)->ret;
2834         mgreg_t res = ((DynCallArgs*)buf)->res;
2835         mgreg_t res2 = ((DynCallArgs*)buf)->res2;
2836
2837         switch (ptype->type) {
2838         case MONO_TYPE_VOID:
2839                 *(gpointer*)ret = NULL;
2840                 break;
2841         case MONO_TYPE_STRING:
2842         case MONO_TYPE_CLASS:  
2843         case MONO_TYPE_ARRAY:
2844         case MONO_TYPE_SZARRAY:
2845         case MONO_TYPE_OBJECT:
2846         case MONO_TYPE_I:
2847         case MONO_TYPE_U:
2848         case MONO_TYPE_PTR:
2849                 *(gpointer*)ret = (gpointer)res;
2850                 break;
2851         case MONO_TYPE_I1:
2852                 *(gint8*)ret = res;
2853                 break;
2854         case MONO_TYPE_U1:
2855         case MONO_TYPE_BOOLEAN:
2856                 *(guint8*)ret = res;
2857                 break;
2858         case MONO_TYPE_I2:
2859                 *(gint16*)ret = res;
2860                 break;
2861         case MONO_TYPE_U2:
2862         case MONO_TYPE_CHAR:
2863                 *(guint16*)ret = res;
2864                 break;
2865         case MONO_TYPE_I4:
2866                 *(gint32*)ret = res;
2867                 break;
2868         case MONO_TYPE_U4:
2869                 *(guint32*)ret = res;
2870                 break;
2871         case MONO_TYPE_I8:
2872         case MONO_TYPE_U8:
2873                 /* This handles endianness as well */
2874                 ((gint32*)ret) [0] = res;
2875                 ((gint32*)ret) [1] = res2;
2876                 break;
2877         case MONO_TYPE_GENERICINST:
2878                 if (MONO_TYPE_IS_REFERENCE (ptype)) {
2879                         *(gpointer*)ret = (gpointer)res;
2880                         break;
2881                 } else {
2882                         /* Fall though */
2883                 }
2884         case MONO_TYPE_VALUETYPE:
2885                 g_assert (ainfo->cinfo->vtype_retaddr);
2886                 /* Nothing to do */
2887                 break;
2888         case MONO_TYPE_R4:
2889                 g_assert (IS_VFP);
2890                 *(float*)ret = *(float*)&res;
2891                 break;
2892         case MONO_TYPE_R8: {
2893                 mgreg_t regs [2];
2894
2895                 g_assert (IS_VFP);
2896                 regs [0] = res;
2897                 regs [1] = res2;
2898
2899                 *(double*)ret = *(double*)&regs;
2900                 break;
2901         }
2902         default:
2903                 g_assert_not_reached ();
2904         }
2905 }
2906
2907 #ifndef DISABLE_JIT
2908
2909 /*
2910  * Allow tracing to work with this interface (with an optional argument)
2911  */
2912
2913 void*
2914 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
2915 {
2916         guchar *code = p;
2917
2918         code = mono_arm_emit_load_imm (code, ARMREG_R0, (guint32)cfg->method);
2919         ARM_MOV_REG_IMM8 (code, ARMREG_R1, 0); /* NULL ebp for now */
2920         code = mono_arm_emit_load_imm (code, ARMREG_R2, (guint32)func);
2921         code = emit_call_reg (code, ARMREG_R2);
2922         return code;
2923 }
2924
2925 enum {
2926         SAVE_NONE,
2927         SAVE_STRUCT,
2928         SAVE_ONE,
2929         SAVE_TWO,
2930         SAVE_ONE_FP,
2931         SAVE_TWO_FP
2932 };
2933
2934 void*
2935 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
2936 {
2937         guchar *code = p;
2938         int save_mode = SAVE_NONE;
2939         int offset;
2940         MonoMethod *method = cfg->method;
2941         MonoType *ret_type = mini_type_get_underlying_type (cfg->generic_sharing_context, mono_method_signature (method)->ret);
2942         int rtype = ret_type->type;
2943         int save_offset = cfg->param_area;
2944         save_offset += 7;
2945         save_offset &= ~7;
2946         
2947         offset = code - cfg->native_code;
2948         /* we need about 16 instructions */
2949         if (offset > (cfg->code_size - 16 * 4)) {
2950                 cfg->code_size *= 2;
2951                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2952                 code = cfg->native_code + offset;
2953         }
2954         switch (rtype) {
2955         case MONO_TYPE_VOID:
2956                 /* special case string .ctor icall */
2957                 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
2958                         save_mode = SAVE_ONE;
2959                 else
2960                         save_mode = SAVE_NONE;
2961                 break;
2962         case MONO_TYPE_I8:
2963         case MONO_TYPE_U8:
2964                 save_mode = SAVE_TWO;
2965                 break;
2966         case MONO_TYPE_R4:
2967                 if (IS_HARD_FLOAT)
2968                         save_mode = SAVE_ONE_FP;
2969                 else
2970                         save_mode = SAVE_ONE;
2971                 break;
2972         case MONO_TYPE_R8:
2973                 if (IS_HARD_FLOAT)
2974                         save_mode = SAVE_TWO_FP;
2975                 else
2976                         save_mode = SAVE_TWO;
2977                 break;
2978         case MONO_TYPE_GENERICINST:
2979                 if (!mono_type_generic_inst_is_valuetype (ret_type)) {
2980                         save_mode = SAVE_ONE;
2981                         break;
2982                 }
2983                 /* Fall through */
2984         case MONO_TYPE_VALUETYPE:
2985                 save_mode = SAVE_STRUCT;
2986                 break;
2987         default:
2988                 save_mode = SAVE_ONE;
2989                 break;
2990         }
2991
2992         switch (save_mode) {
2993         case SAVE_TWO:
2994                 ARM_STR_IMM (code, ARMREG_R0, cfg->frame_reg, save_offset);
2995                 ARM_STR_IMM (code, ARMREG_R1, cfg->frame_reg, save_offset + 4);
2996                 if (enable_arguments) {
2997                         ARM_MOV_REG_REG (code, ARMREG_R2, ARMREG_R1);
2998                         ARM_MOV_REG_REG (code, ARMREG_R1, ARMREG_R0);
2999                 }
3000                 break;
3001         case SAVE_ONE:
3002                 ARM_STR_IMM (code, ARMREG_R0, cfg->frame_reg, save_offset);
3003                 if (enable_arguments) {
3004                         ARM_MOV_REG_REG (code, ARMREG_R1, ARMREG_R0);
3005                 }
3006                 break;
3007         case SAVE_ONE_FP:
3008                 ARM_FSTS (code, ARM_VFP_F0, cfg->frame_reg, save_offset);
3009                 if (enable_arguments) {
3010                         ARM_FMRS (code, ARMREG_R1, ARM_VFP_F0);
3011                 }
3012                 break;
3013         case SAVE_TWO_FP:
3014                 ARM_FSTD (code, ARM_VFP_D0, cfg->frame_reg, save_offset);
3015                 if (enable_arguments) {
3016                         ARM_FMDRR (code, ARMREG_R1, ARMREG_R2, ARM_VFP_D0);
3017                 }
3018                 break;
3019         case SAVE_STRUCT:
3020                 if (enable_arguments) {
3021                         /* FIXME: get the actual address  */
3022                         ARM_MOV_REG_REG (code, ARMREG_R1, ARMREG_R0);
3023                 }
3024                 break;
3025         case SAVE_NONE:
3026         default:
3027                 break;
3028         }
3029
3030         code = mono_arm_emit_load_imm (code, ARMREG_R0, (guint32)cfg->method);
3031         code = mono_arm_emit_load_imm (code, ARMREG_IP, (guint32)func);
3032         code = emit_call_reg (code, ARMREG_IP);
3033
3034         switch (save_mode) {
3035         case SAVE_TWO:
3036                 ARM_LDR_IMM (code, ARMREG_R0, cfg->frame_reg, save_offset);
3037                 ARM_LDR_IMM (code, ARMREG_R1, cfg->frame_reg, save_offset + 4);
3038                 break;
3039         case SAVE_ONE:
3040                 ARM_LDR_IMM (code, ARMREG_R0, cfg->frame_reg, save_offset);
3041                 break;
3042         case SAVE_ONE_FP:
3043                 ARM_FLDS (code, ARM_VFP_F0, cfg->frame_reg, save_offset);
3044                 break;
3045         case SAVE_TWO_FP:
3046                 ARM_FLDD (code, ARM_VFP_D0, cfg->frame_reg, save_offset);
3047                 break;
3048         case SAVE_NONE:
3049         default:
3050                 break;
3051         }
3052
3053         return code;
3054 }
3055
3056 /*
3057  * The immediate field for cond branches is big enough for all reasonable methods
3058  */
3059 #define EMIT_COND_BRANCH_FLAGS(ins,condcode) \
3060 if (0 && ins->inst_true_bb->native_offset) { \
3061         ARM_B_COND (code, (condcode), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffffff); \
3062 } else { \
3063         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
3064         ARM_B_COND (code, (condcode), 0); \
3065 }
3066
3067 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_cc_table [(cond)])
3068
3069 /* emit an exception if condition is fail
3070  *
3071  * We assign the extra code used to throw the implicit exceptions
3072  * to cfg->bb_exit as far as the big branch handling is concerned
3073  */
3074 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(condcode,exc_name)            \
3075         do {                                                        \
3076                 mono_add_patch_info (cfg, code - cfg->native_code,   \
3077                                     MONO_PATCH_INFO_EXC, exc_name); \
3078                 ARM_BL_COND (code, (condcode), 0); \
3079         } while (0); 
3080
3081 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_cc_table [(cond)], (exc_name))
3082
3083 void
3084 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
3085 {
3086 }
3087
3088 void
3089 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
3090 {
3091         MonoInst *ins, *n, *last_ins = NULL;
3092
3093         MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
3094                 switch (ins->opcode) {
3095                 case OP_MUL_IMM: 
3096                 case OP_IMUL_IMM: 
3097                         /* Already done by an arch-independent pass */
3098                         break;
3099                 case OP_LOAD_MEMBASE:
3100                 case OP_LOADI4_MEMBASE:
3101                         /* 
3102                          * OP_STORE_MEMBASE_REG reg, offset(basereg) 
3103                          * OP_LOAD_MEMBASE offset(basereg), reg
3104                          */
3105                         if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG 
3106                                          || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
3107                             ins->inst_basereg == last_ins->inst_destbasereg &&
3108                             ins->inst_offset == last_ins->inst_offset) {
3109                                 if (ins->dreg == last_ins->sreg1) {
3110                                         MONO_DELETE_INS (bb, ins);
3111                                         continue;
3112                                 } else {
3113                                         //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
3114                                         ins->opcode = OP_MOVE;
3115                                         ins->sreg1 = last_ins->sreg1;
3116                                 }
3117
3118                         /* 
3119                          * Note: reg1 must be different from the basereg in the second load
3120                          * OP_LOAD_MEMBASE offset(basereg), reg1
3121                          * OP_LOAD_MEMBASE offset(basereg), reg2
3122                          * -->
3123                          * OP_LOAD_MEMBASE offset(basereg), reg1
3124                          * OP_MOVE reg1, reg2
3125                          */
3126                         } if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
3127                                            || last_ins->opcode == OP_LOAD_MEMBASE) &&
3128                               ins->inst_basereg != last_ins->dreg &&
3129                               ins->inst_basereg == last_ins->inst_basereg &&
3130                               ins->inst_offset == last_ins->inst_offset) {
3131
3132                                 if (ins->dreg == last_ins->dreg) {
3133                                         MONO_DELETE_INS (bb, ins);
3134                                         continue;
3135                                 } else {
3136                                         ins->opcode = OP_MOVE;
3137                                         ins->sreg1 = last_ins->dreg;
3138                                 }
3139
3140                                 //g_assert_not_reached ();
3141
3142 #if 0
3143                         /* 
3144                          * OP_STORE_MEMBASE_IMM imm, offset(basereg) 
3145                          * OP_LOAD_MEMBASE offset(basereg), reg
3146                          * -->
3147                          * OP_STORE_MEMBASE_IMM imm, offset(basereg) 
3148                          * OP_ICONST reg, imm
3149                          */
3150                         } else if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
3151                                                 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
3152                                    ins->inst_basereg == last_ins->inst_destbasereg &&
3153                                    ins->inst_offset == last_ins->inst_offset) {
3154                                 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
3155                                 ins->opcode = OP_ICONST;
3156                                 ins->inst_c0 = last_ins->inst_imm;
3157                                 g_assert_not_reached (); // check this rule
3158 #endif
3159                         }
3160                         break;
3161                 case OP_LOADU1_MEMBASE:
3162                 case OP_LOADI1_MEMBASE:
3163                         if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
3164                                         ins->inst_basereg == last_ins->inst_destbasereg &&
3165                                         ins->inst_offset == last_ins->inst_offset) {
3166                                 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
3167                                 ins->sreg1 = last_ins->sreg1;                           
3168                         }
3169                         break;
3170                 case OP_LOADU2_MEMBASE:
3171                 case OP_LOADI2_MEMBASE:
3172                         if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
3173                                         ins->inst_basereg == last_ins->inst_destbasereg &&
3174                                         ins->inst_offset == last_ins->inst_offset) {
3175                                 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
3176                                 ins->sreg1 = last_ins->sreg1;                           
3177                         }
3178                         break;
3179                 case OP_MOVE:
3180                         ins->opcode = OP_MOVE;
3181                         /* 
3182                          * OP_MOVE reg, reg 
3183                          */
3184                         if (ins->dreg == ins->sreg1) {
3185                                 MONO_DELETE_INS (bb, ins);
3186                                 continue;
3187                         }
3188                         /* 
3189                          * OP_MOVE sreg, dreg 
3190                          * OP_MOVE dreg, sreg
3191                          */
3192                         if (last_ins && last_ins->opcode == OP_MOVE &&
3193                             ins->sreg1 == last_ins->dreg &&
3194                             ins->dreg == last_ins->sreg1) {
3195                                 MONO_DELETE_INS (bb, ins);
3196                                 continue;
3197                         }
3198                         break;
3199                 }
3200                 last_ins = ins;
3201                 ins = ins->next;
3202         }
3203         bb->last_ins = last_ins;
3204 }
3205
3206 /* 
3207  * the branch_cc_table should maintain the order of these
3208  * opcodes.
3209 case CEE_BEQ:
3210 case CEE_BGE:
3211 case CEE_BGT:
3212 case CEE_BLE:
3213 case CEE_BLT:
3214 case CEE_BNE_UN:
3215 case CEE_BGE_UN:
3216 case CEE_BGT_UN:
3217 case CEE_BLE_UN:
3218 case CEE_BLT_UN:
3219  */
3220 static const guchar 
3221 branch_cc_table [] = {
3222         ARMCOND_EQ, 
3223         ARMCOND_GE, 
3224         ARMCOND_GT, 
3225         ARMCOND_LE,
3226         ARMCOND_LT, 
3227         
3228         ARMCOND_NE, 
3229         ARMCOND_HS, 
3230         ARMCOND_HI, 
3231         ARMCOND_LS,
3232         ARMCOND_LO
3233 };
3234
3235 #define ADD_NEW_INS(cfg,dest,op) do {       \
3236                 MONO_INST_NEW ((cfg), (dest), (op)); \
3237         mono_bblock_insert_before_ins (bb, ins, (dest)); \
3238         } while (0)
3239
3240 static int
3241 map_to_reg_reg_op (int op)
3242 {
3243         switch (op) {
3244         case OP_ADD_IMM:
3245                 return OP_IADD;
3246         case OP_SUB_IMM:
3247                 return OP_ISUB;
3248         case OP_AND_IMM:
3249                 return OP_IAND;
3250         case OP_COMPARE_IMM:
3251                 return OP_COMPARE;
3252         case OP_ICOMPARE_IMM:
3253                 return OP_ICOMPARE;
3254         case OP_ADDCC_IMM:
3255                 return OP_ADDCC;
3256         case OP_ADC_IMM:
3257                 return OP_ADC;
3258         case OP_SUBCC_IMM:
3259                 return OP_SUBCC;
3260         case OP_SBB_IMM:
3261                 return OP_SBB;
3262         case OP_OR_IMM:
3263                 return OP_IOR;
3264         case OP_XOR_IMM:
3265                 return OP_IXOR;
3266         case OP_LOAD_MEMBASE:
3267                 return OP_LOAD_MEMINDEX;
3268         case OP_LOADI4_MEMBASE:
3269                 return OP_LOADI4_MEMINDEX;
3270         case OP_LOADU4_MEMBASE:
3271                 return OP_LOADU4_MEMINDEX;
3272         case OP_LOADU1_MEMBASE:
3273                 return OP_LOADU1_MEMINDEX;
3274         case OP_LOADI2_MEMBASE:
3275                 return OP_LOADI2_MEMINDEX;
3276         case OP_LOADU2_MEMBASE:
3277                 return OP_LOADU2_MEMINDEX;
3278         case OP_LOADI1_MEMBASE:
3279                 return OP_LOADI1_MEMINDEX;
3280         case OP_STOREI1_MEMBASE_REG:
3281                 return OP_STOREI1_MEMINDEX;
3282         case OP_STOREI2_MEMBASE_REG:
3283                 return OP_STOREI2_MEMINDEX;
3284         case OP_STOREI4_MEMBASE_REG:
3285                 return OP_STOREI4_MEMINDEX;
3286         case OP_STORE_MEMBASE_REG:
3287                 return OP_STORE_MEMINDEX;
3288         case OP_STORER4_MEMBASE_REG:
3289                 return OP_STORER4_MEMINDEX;
3290         case OP_STORER8_MEMBASE_REG:
3291                 return OP_STORER8_MEMINDEX;
3292         case OP_STORE_MEMBASE_IMM:
3293                 return OP_STORE_MEMBASE_REG;
3294         case OP_STOREI1_MEMBASE_IMM:
3295                 return OP_STOREI1_MEMBASE_REG;
3296         case OP_STOREI2_MEMBASE_IMM:
3297                 return OP_STOREI2_MEMBASE_REG;
3298         case OP_STOREI4_MEMBASE_IMM:
3299                 return OP_STOREI4_MEMBASE_REG;
3300         }
3301         g_assert_not_reached ();
3302 }
3303
3304 /*
3305  * Remove from the instruction list the instructions that can't be
3306  * represented with very simple instructions with no register
3307  * requirements.
3308  */
3309 void
3310 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
3311 {
3312         MonoInst *ins, *temp, *last_ins = NULL;
3313         int rot_amount, imm8, low_imm;
3314
3315         MONO_BB_FOR_EACH_INS (bb, ins) {
3316 loop_start:
3317                 switch (ins->opcode) {
3318                 case OP_ADD_IMM:
3319                 case OP_SUB_IMM:
3320                 case OP_AND_IMM:
3321                 case OP_COMPARE_IMM:
3322                 case OP_ICOMPARE_IMM:
3323                 case OP_ADDCC_IMM:
3324                 case OP_ADC_IMM:
3325                 case OP_SUBCC_IMM:
3326                 case OP_SBB_IMM:
3327                 case OP_OR_IMM:
3328                 case OP_XOR_IMM:
3329                 case OP_IADD_IMM:
3330                 case OP_ISUB_IMM:
3331                 case OP_IAND_IMM:
3332                 case OP_IADC_IMM:
3333                 case OP_ISBB_IMM:
3334                 case OP_IOR_IMM:
3335                 case OP_IXOR_IMM:
3336                         if ((imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount)) < 0) {
3337                                 ADD_NEW_INS (cfg, temp, OP_ICONST);
3338                                 temp->inst_c0 = ins->inst_imm;
3339                                 temp->dreg = mono_alloc_ireg (cfg);
3340                                 ins->sreg2 = temp->dreg;
3341                                 ins->opcode = mono_op_imm_to_op (ins->opcode);
3342                         }
3343                         if (ins->opcode == OP_SBB || ins->opcode == OP_ISBB || ins->opcode == OP_SUBCC)
3344                                 goto loop_start;
3345                         else
3346                                 break;
3347                 case OP_MUL_IMM:
3348                 case OP_IMUL_IMM:
3349                         if (ins->inst_imm == 1) {
3350                                 ins->opcode = OP_MOVE;
3351                                 break;
3352                         }
3353                         if (ins->inst_imm == 0) {
3354                                 ins->opcode = OP_ICONST;
3355                                 ins->inst_c0 = 0;
3356                                 break;
3357                         }
3358                         imm8 = mono_is_power_of_two (ins->inst_imm);
3359                         if (imm8 > 0) {
3360                                 ins->opcode = OP_SHL_IMM;
3361                                 ins->inst_imm = imm8;
3362                                 break;
3363                         }
3364                         ADD_NEW_INS (cfg, temp, OP_ICONST);
3365                         temp->inst_c0 = ins->inst_imm;
3366                         temp->dreg = mono_alloc_ireg (cfg);
3367                         ins->sreg2 = temp->dreg;
3368                         ins->opcode = OP_IMUL;
3369                         break;
3370                 case OP_SBB:
3371                 case OP_ISBB:
3372                 case OP_SUBCC:
3373                 case OP_ISUBCC:
3374                         if (ins->next  && (ins->next->opcode == OP_COND_EXC_C || ins->next->opcode == OP_COND_EXC_IC))
3375                                 /* ARM sets the C flag to 1 if there was _no_ overflow */
3376                                 ins->next->opcode = OP_COND_EXC_NC;
3377                         break;
3378                 case OP_IDIV_IMM:
3379                 case OP_IDIV_UN_IMM:
3380                 case OP_IREM_IMM:
3381                 case OP_IREM_UN_IMM:
3382                         ADD_NEW_INS (cfg, temp, OP_ICONST);
3383                         temp->inst_c0 = ins->inst_imm;
3384                         temp->dreg = mono_alloc_ireg (cfg);
3385                         ins->sreg2 = temp->dreg;
3386                         ins->opcode = mono_op_imm_to_op (ins->opcode);
3387                         break;
3388                 case OP_LOCALLOC_IMM:
3389                         ADD_NEW_INS (cfg, temp, OP_ICONST);
3390                         temp->inst_c0 = ins->inst_imm;
3391                         temp->dreg = mono_alloc_ireg (cfg);
3392                         ins->sreg1 = temp->dreg;
3393                         ins->opcode = OP_LOCALLOC;
3394                         break;
3395                 case OP_LOAD_MEMBASE:
3396                 case OP_LOADI4_MEMBASE:
3397                 case OP_LOADU4_MEMBASE:
3398                 case OP_LOADU1_MEMBASE:
3399                         /* we can do two things: load the immed in a register
3400                          * and use an indexed load, or see if the immed can be
3401                          * represented as an ad_imm + a load with a smaller offset
3402                          * that fits. We just do the first for now, optimize later.
3403                          */
3404                         if (arm_is_imm12 (ins->inst_offset))
3405                                 break;
3406                         ADD_NEW_INS (cfg, temp, OP_ICONST);
3407                         temp->inst_c0 = ins->inst_offset;
3408                         temp->dreg = mono_alloc_ireg (cfg);
3409                         ins->sreg2 = temp->dreg;
3410                         ins->opcode = map_to_reg_reg_op (ins->opcode);
3411                         break;
3412                 case OP_LOADI2_MEMBASE:
3413                 case OP_LOADU2_MEMBASE:
3414                 case OP_LOADI1_MEMBASE:
3415                         if (arm_is_imm8 (ins->inst_offset))
3416                                 break;
3417                         ADD_NEW_INS (cfg, temp, OP_ICONST);
3418                         temp->inst_c0 = ins->inst_offset;
3419                         temp->dreg = mono_alloc_ireg (cfg);
3420                         ins->sreg2 = temp->dreg;
3421                         ins->opcode = map_to_reg_reg_op (ins->opcode);
3422                         break;
3423                 case OP_LOADR4_MEMBASE:
3424                 case OP_LOADR8_MEMBASE:
3425                         if (arm_is_fpimm8 (ins->inst_offset))
3426                                 break;
3427                         low_imm = ins->inst_offset & 0x1ff;
3428                         if ((imm8 = mono_arm_is_rotated_imm8 (ins->inst_offset & ~0x1ff, &rot_amount)) >= 0) {
3429                                 ADD_NEW_INS (cfg, temp, OP_ADD_IMM);
3430                                 temp->inst_imm = ins->inst_offset & ~0x1ff;
3431                                 temp->sreg1 = ins->inst_basereg;
3432                                 temp->dreg = mono_alloc_ireg (cfg);
3433                                 ins->inst_basereg = temp->dreg;
3434                                 ins->inst_offset = low_imm;
3435                         } else {
3436                                 MonoInst *add_ins;
3437
3438                                 ADD_NEW_INS (cfg, temp, OP_ICONST);
3439                                 temp->inst_c0 = ins->inst_offset;
3440                                 temp->dreg = mono_alloc_ireg (cfg);
3441
3442                                 ADD_NEW_INS (cfg, add_ins, OP_IADD);
3443                                 add_ins->sreg1 = ins->inst_basereg;
3444                                 add_ins->sreg2 = temp->dreg;
3445                                 add_ins->dreg = mono_alloc_ireg (cfg);
3446
3447                                 ins->inst_basereg = add_ins->dreg;
3448                                 ins->inst_offset = 0;
3449                         }
3450                         break;
3451                 case OP_STORE_MEMBASE_REG:
3452                 case OP_STOREI4_MEMBASE_REG:
3453                 case OP_STOREI1_MEMBASE_REG:
3454                         if (arm_is_imm12 (ins->inst_offset))
3455                                 break;
3456                         ADD_NEW_INS (cfg, temp, OP_ICONST);
3457                         temp->inst_c0 = ins->inst_offset;
3458                         temp->dreg = mono_alloc_ireg (cfg);
3459                         ins->sreg2 = temp->dreg;
3460                         ins->opcode = map_to_reg_reg_op (ins->opcode);
3461                         break;
3462                 case OP_STOREI2_MEMBASE_REG:
3463                         if (arm_is_imm8 (ins->inst_offset))
3464                                 break;
3465                         ADD_NEW_INS (cfg, temp, OP_ICONST);
3466                         temp->inst_c0 = ins->inst_offset;
3467                         temp->dreg = mono_alloc_ireg (cfg);
3468                         ins->sreg2 = temp->dreg;
3469                         ins->opcode = map_to_reg_reg_op (ins->opcode);
3470                         break;
3471                 case OP_STORER4_MEMBASE_REG:
3472                 case OP_STORER8_MEMBASE_REG:
3473                         if (arm_is_fpimm8 (ins->inst_offset))
3474                                 break;
3475                         low_imm = ins->inst_offset & 0x1ff;
3476                         if ((imm8 = mono_arm_is_rotated_imm8 (ins->inst_offset & ~ 0x1ff, &rot_amount)) >= 0 && arm_is_fpimm8 (low_imm)) {
3477                                 ADD_NEW_INS (cfg, temp, OP_ADD_IMM);
3478                                 temp->inst_imm = ins->inst_offset & ~0x1ff;
3479                                 temp->sreg1 = ins->inst_destbasereg;
3480                                 temp->dreg = mono_alloc_ireg (cfg);
3481                                 ins->inst_destbasereg = temp->dreg;
3482                                 ins->inst_offset = low_imm;
3483                         } else {
3484                                 MonoInst *add_ins;
3485
3486                                 ADD_NEW_INS (cfg, temp, OP_ICONST);
3487                                 temp->inst_c0 = ins->inst_offset;
3488                                 temp->dreg = mono_alloc_ireg (cfg);
3489
3490                                 ADD_NEW_INS (cfg, add_ins, OP_IADD);
3491                                 add_ins->sreg1 = ins->inst_destbasereg;
3492                                 add_ins->sreg2 = temp->dreg;
3493                                 add_ins->dreg = mono_alloc_ireg (cfg);
3494
3495                                 ins->inst_destbasereg = add_ins->dreg;
3496                                 ins->inst_offset = 0;
3497                         }
3498                         break;
3499                 case OP_STORE_MEMBASE_IMM:
3500                 case OP_STOREI1_MEMBASE_IMM:
3501                 case OP_STOREI2_MEMBASE_IMM:
3502                 case OP_STOREI4_MEMBASE_IMM:
3503                         ADD_NEW_INS (cfg, temp, OP_ICONST);
3504                         temp->inst_c0 = ins->inst_imm;
3505                         temp->dreg = mono_alloc_ireg (cfg);
3506                         ins->sreg1 = temp->dreg;
3507                         ins->opcode = map_to_reg_reg_op (ins->opcode);
3508                         last_ins = temp;
3509                         goto loop_start; /* make it handle the possibly big ins->inst_offset */
3510                 case OP_FCOMPARE: {
3511                         gboolean swap = FALSE;
3512                         int reg;
3513
3514                         if (!ins->next) {
3515                                 /* Optimized away */
3516                                 NULLIFY_INS (ins);
3517                                 break;
3518                         }
3519
3520                         /* Some fp compares require swapped operands */
3521                         switch (ins->next->opcode) {
3522                         case OP_FBGT:
3523                                 ins->next->opcode = OP_FBLT;
3524                                 swap = TRUE;
3525                                 break;
3526                         case OP_FBGT_UN:
3527                                 ins->next->opcode = OP_FBLT_UN;
3528                                 swap = TRUE;
3529                                 break;
3530                         case OP_FBLE:
3531                                 ins->next->opcode = OP_FBGE;
3532                                 swap = TRUE;
3533                                 break;
3534                         case OP_FBLE_UN:
3535                                 ins->next->opcode = OP_FBGE_UN;
3536                                 swap = TRUE;
3537                                 break;
3538                         default:
3539                                 break;
3540                         }
3541                         if (swap) {
3542                                 reg = ins->sreg1;
3543                                 ins->sreg1 = ins->sreg2;
3544                                 ins->sreg2 = reg;
3545                         }
3546                         break;
3547                 }
3548                 }
3549
3550                 last_ins = ins;
3551         }
3552         bb->last_ins = last_ins;
3553         bb->max_vreg = cfg->next_vreg;
3554 }
3555
3556 void
3557 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *long_ins)
3558 {
3559         MonoInst *ins;
3560
3561         if (long_ins->opcode == OP_LNEG) {
3562                 ins = long_ins;
3563                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ARM_RSBS_IMM, ins->dreg + 1, ins->sreg1 + 1, 0);
3564                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ARM_RSC_IMM, ins->dreg + 2, ins->sreg1 + 2, 0);
3565                 NULLIFY_INS (ins);
3566         }
3567 }
3568
3569 static guchar*
3570 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
3571 {
3572         /* sreg is a float, dreg is an integer reg  */
3573         if (IS_VFP) {
3574                 code = mono_arm_emit_vfp_scratch_save (cfg, code, vfp_scratch1);
3575                 if (is_signed)
3576                         ARM_TOSIZD (code, vfp_scratch1, sreg);
3577                 else
3578                         ARM_TOUIZD (code, vfp_scratch1, sreg);
3579                 ARM_FMRS (code, dreg, vfp_scratch1);
3580                 code = mono_arm_emit_vfp_scratch_restore (cfg, code, vfp_scratch1);
3581         }
3582         if (!is_signed) {
3583                 if (size == 1)
3584                         ARM_AND_REG_IMM8 (code, dreg, dreg, 0xff);
3585                 else if (size == 2) {
3586                         ARM_SHL_IMM (code, dreg, dreg, 16);
3587                         ARM_SHR_IMM (code, dreg, dreg, 16);
3588                 }
3589         } else {
3590                 if (size == 1) {
3591                         ARM_SHL_IMM (code, dreg, dreg, 24);
3592                         ARM_SAR_IMM (code, dreg, dreg, 24);
3593                 } else if (size == 2) {
3594                         ARM_SHL_IMM (code, dreg, dreg, 16);
3595                         ARM_SAR_IMM (code, dreg, dreg, 16);
3596                 }
3597         }
3598         return code;
3599 }
3600
3601 #endif /* #ifndef DISABLE_JIT */
3602
3603 typedef struct {
3604         guchar *code;
3605         const guchar *target;
3606         int absolute;
3607         int found;
3608 } PatchData;
3609
3610 #define is_call_imm(diff) ((gint)(diff) >= -33554432 && (gint)(diff) <= 33554431)
3611
3612 static int
3613 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
3614         PatchData *pdata = (PatchData*)user_data;
3615         guchar *code = data;
3616         guint32 *thunks = data;
3617         guint32 *endthunks = (guint32*)(code + bsize);
3618         int count = 0;
3619         int difflow, diffhigh;
3620
3621         /* always ensure a call from pdata->code can reach to the thunks without further thunks */
3622         difflow = (char*)pdata->code - (char*)thunks;
3623         diffhigh = (char*)pdata->code - (char*)endthunks;
3624         if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
3625                 return 0;
3626
3627         /*
3628          * The thunk is composed of 3 words:
3629          * load constant from thunks [2] into ARM_IP
3630          * bx to ARM_IP
3631          * address constant
3632          * Note that the LR register is already setup
3633          */
3634         //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
3635         if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
3636                 while (thunks < endthunks) {
3637                         //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
3638                         if (thunks [2] == (guint32)pdata->target) {
3639                                 arm_patch (pdata->code, (guchar*)thunks);
3640                                 mono_arch_flush_icache (pdata->code, 4);
3641                                 pdata->found = 1;
3642                                 return 1;
3643                         } else if ((thunks [0] == 0) && (thunks [1] == 0) && (thunks [2] == 0)) {
3644                                 /* found a free slot instead: emit thunk */
3645                                 /* ARMREG_IP is fine to use since this can't be an IMT call
3646                                  * which is indirect
3647                                  */
3648                                 code = (guchar*)thunks;
3649                                 ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0);
3650                                 if (thumb_supported)
3651                                         ARM_BX (code, ARMREG_IP);
3652                                 else
3653                                         ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
3654                                 thunks [2] = (guint32)pdata->target;
3655                                 mono_arch_flush_icache ((guchar*)thunks, 12);
3656
3657                                 arm_patch (pdata->code, (guchar*)thunks);
3658                                 mono_arch_flush_icache (pdata->code, 4);
3659                                 pdata->found = 1;
3660                                 return 1;
3661                         }
3662                         /* skip 12 bytes, the size of the thunk */
3663                         thunks += 3;
3664                         count++;
3665                 }
3666                 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
3667         }
3668         return 0;
3669 }
3670
3671 static void
3672 handle_thunk (MonoDomain *domain, int absolute, guchar *code, const guchar *target, MonoCodeManager *dyn_code_mp)
3673 {
3674         PatchData pdata;
3675
3676         if (!domain)
3677                 domain = mono_domain_get ();
3678
3679         pdata.code = code;
3680         pdata.target = target;
3681         pdata.absolute = absolute;
3682         pdata.found = 0;
3683
3684         if (dyn_code_mp) {
3685                 mono_code_manager_foreach (dyn_code_mp, search_thunk_slot, &pdata);
3686         }
3687
3688         if (pdata.found != 1) {
3689                 mono_domain_lock (domain);
3690                 mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
3691
3692                 if (!pdata.found) {
3693                         /* this uses the first available slot */
3694                         pdata.found = 2;
3695                         mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
3696                 }
3697                 mono_domain_unlock (domain);
3698         }
3699
3700         if (pdata.found != 1) {
3701                 GHashTable *hash;
3702                 GHashTableIter iter;
3703                 MonoJitDynamicMethodInfo *ji;
3704
3705                 /*
3706                  * This might be a dynamic method, search its code manager. We can only
3707                  * use the dynamic method containing CODE, since the others might be freed later.
3708                  */
3709                 pdata.found = 0;
3710
3711                 mono_domain_lock (domain);
3712                 hash = domain_jit_info (domain)->dynamic_code_hash;
3713                 if (hash) {
3714                         /* FIXME: Speed this up */
3715                         g_hash_table_iter_init (&iter, hash);
3716                         while (g_hash_table_iter_next (&iter, NULL, (gpointer*)&ji)) {
3717                                 mono_code_manager_foreach (ji->code_mp, search_thunk_slot, &pdata);
3718                                 if (pdata.found == 1)
3719                                         break;
3720                         }
3721                 }
3722                 mono_domain_unlock (domain);
3723         }
3724         if (pdata.found != 1)
3725                 g_print ("thunk failed for %p from %p\n", target, code);
3726         g_assert (pdata.found == 1);
3727 }
3728
3729 static void
3730 arm_patch_general (MonoDomain *domain, guchar *code, const guchar *target, MonoCodeManager *dyn_code_mp)
3731 {
3732         guint32 *code32 = (void*)code;
3733         guint32 ins = *code32;
3734         guint32 prim = (ins >> 25) & 7;
3735         guint32 tval = GPOINTER_TO_UINT (target);
3736
3737         //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
3738         if (prim == 5) { /* 101b */
3739                 /* the diff starts 8 bytes from the branch opcode */
3740                 gint diff = target - code - 8;
3741                 gint tbits;
3742                 gint tmask = 0xffffffff;
3743                 if (tval & 1) { /* entering thumb mode */
3744                         diff = target - 1 - code - 8;
3745                         g_assert (thumb_supported);
3746                         tbits = 0xf << 28; /* bl->blx bit pattern */
3747                         g_assert ((ins & (1 << 24))); /* it must be a bl, not b instruction */
3748                         /* this low bit of the displacement is moved to bit 24 in the instruction encoding */
3749                         if (diff & 2) {
3750                                 tbits |= 1 << 24;
3751                         }
3752                         tmask = ~(1 << 24); /* clear the link bit */
3753                         /*g_print ("blx to thumb: target: %p, code: %p, diff: %d, mask: %x\n", target, code, diff, tmask);*/
3754                 } else {
3755                         tbits = 0;
3756                 }
3757                 if (diff >= 0) {
3758                         if (diff <= 33554431) {
3759                                 diff >>= 2;
3760                                 ins = (ins & 0xff000000) | diff;
3761                                 ins &= tmask;
3762                                 *code32 = ins | tbits;
3763                                 return;
3764                         }
3765                 } else {
3766                         /* diff between 0 and -33554432 */
3767                         if (diff >= -33554432) {
3768                                 diff >>= 2;
3769                                 ins = (ins & 0xff000000) | (diff & ~0xff000000);
3770                                 ins &= tmask;
3771                                 *code32 = ins | tbits;
3772                                 return;
3773                         }
3774                 }
3775                 
3776                 handle_thunk (domain, TRUE, code, target, dyn_code_mp);
3777                 return;
3778         }
3779
3780 #ifdef USE_JUMP_TABLES
3781         {
3782                 gpointer *jte = mono_jumptable_get_entry (code);
3783                 g_assert (jte);
3784                 jte [0] = (gpointer) target;
3785         }
3786 #else
3787         /*
3788          * The alternative call sequences looks like this:
3789          *
3790          *      ldr ip, [pc] // loads the address constant
3791          *      b 1f         // jumps around the constant
3792          *      address constant embedded in the code
3793          *   1f:
3794          *      mov lr, pc
3795          *      mov pc, ip
3796          *
3797          * There are two cases for patching:
3798          * a) at the end of method emission: in this case code points to the start
3799          *    of the call sequence
3800          * b) during runtime patching of the call site: in this case code points
3801          *    to the mov pc, ip instruction
3802          *
3803          * We have to handle also the thunk jump code sequence:
3804          *
3805          *      ldr ip, [pc]
3806          *      mov pc, ip
3807          *      address constant // execution never reaches here
3808          */
3809         if ((ins & 0x0ffffff0) == 0x12fff10) {
3810                 /* Branch and exchange: the address is constructed in a reg 
3811                  * We can patch BX when the code sequence is the following:
3812                  *  ldr     ip, [pc, #0]    ; 0x8
3813                  *  b       0xc
3814                  *  .word code_ptr
3815                  *  mov     lr, pc
3816                  *  bx      ips
3817                  * */
3818                 guint32 ccode [4];
3819                 guint8 *emit = (guint8*)ccode;
3820                 ARM_LDR_IMM (emit, ARMREG_IP, ARMREG_PC, 0);
3821                 ARM_B (emit, 0);
3822                 ARM_MOV_REG_REG (emit, ARMREG_LR, ARMREG_PC);
3823                 ARM_BX (emit, ARMREG_IP);
3824
3825                 /*patching from magic trampoline*/
3826                 if (ins == ccode [3]) {
3827                         g_assert (code32 [-4] == ccode [0]);
3828                         g_assert (code32 [-3] == ccode [1]);
3829                         g_assert (code32 [-1] == ccode [2]);
3830                         code32 [-2] = (guint32)target;
3831                         return;
3832                 }
3833                 /*patching from JIT*/
3834                 if (ins == ccode [0]) {
3835                         g_assert (code32 [1] == ccode [1]);
3836                         g_assert (code32 [3] == ccode [2]);
3837                         g_assert (code32 [4] == ccode [3]);
3838                         code32 [2] = (guint32)target;
3839                         return;
3840                 }
3841                 g_assert_not_reached ();
3842         } else if ((ins & 0x0ffffff0) == 0x12fff30) {
3843                 /*
3844                  * ldr ip, [pc, #0]
3845                  * b 0xc
3846                  * .word code_ptr
3847                  * blx ip
3848                  */
3849                 guint32 ccode [4];
3850                 guint8 *emit = (guint8*)ccode;
3851                 ARM_LDR_IMM (emit, ARMREG_IP, ARMREG_PC, 0);
3852                 ARM_B (emit, 0);
3853                 ARM_BLX_REG (emit, ARMREG_IP);
3854
3855                 g_assert (code32 [-3] == ccode [0]);
3856                 g_assert (code32 [-2] == ccode [1]);
3857                 g_assert (code32 [0] == ccode [2]);
3858
3859                 code32 [-1] = (guint32)target;
3860         } else {
3861                 guint32 ccode [4];
3862                 guint32 *tmp = ccode;
3863                 guint8 *emit = (guint8*)tmp;
3864                 ARM_LDR_IMM (emit, ARMREG_IP, ARMREG_PC, 0);
3865                 ARM_MOV_REG_REG (emit, ARMREG_LR, ARMREG_PC);
3866                 ARM_MOV_REG_REG (emit, ARMREG_PC, ARMREG_IP);
3867                 ARM_BX (emit, ARMREG_IP);
3868                 if (ins == ccode [2]) {
3869                         g_assert_not_reached (); // should be -2 ...
3870                         code32 [-1] = (guint32)target;
3871                         return;
3872                 }
3873                 if (ins == ccode [0]) {
3874                         /* handles both thunk jump code and the far call sequence */
3875                         code32 [2] = (guint32)target;
3876                         return;
3877                 }
3878                 g_assert_not_reached ();
3879         }
3880 //      g_print ("patched with 0x%08x\n", ins);
3881 #endif
3882 }
3883
3884 void
3885 arm_patch (guchar *code, const guchar *target)
3886 {
3887         arm_patch_general (NULL, code, target, NULL);
3888 }
3889
3890 /* 
3891  * Return the >= 0 uimm8 value if val can be represented with a byte + rotation
3892  * (with the rotation amount in *rot_amount. rot_amount is already adjusted
3893  * to be used with the emit macros.
3894  * Return -1 otherwise.
3895  */
3896 int
3897 mono_arm_is_rotated_imm8 (guint32 val, gint *rot_amount)
3898 {
3899         guint32 res, i;
3900         for (i = 0; i < 31; i+= 2) {
3901                 res = (val << (32 - i)) | (val >> i);
3902                 if (res & ~0xff)
3903                         continue;
3904                 *rot_amount = i? 32 - i: 0;
3905                 return res;
3906         }
3907         return -1;
3908 }
3909
3910 /*
3911  * Emits in code a sequence of instructions that load the value 'val'
3912  * into the dreg register. Uses at most 4 instructions.
3913  */
3914 guint8*
3915 mono_arm_emit_load_imm (guint8 *code, int dreg, guint32 val)
3916 {
3917         int imm8, rot_amount;
3918 #if 0
3919         ARM_LDR_IMM (code, dreg, ARMREG_PC, 0);
3920         /* skip the constant pool */
3921         ARM_B (code, 0);
3922         *(int*)code = val;
3923         code += 4;
3924         return code;
3925 #endif
3926         if ((imm8 = mono_arm_is_rotated_imm8 (val, &rot_amount)) >= 0) {
3927                 ARM_MOV_REG_IMM (code, dreg, imm8, rot_amount);
3928         } else if ((imm8 = mono_arm_is_rotated_imm8 (~val, &rot_amount)) >= 0) {
3929                 ARM_MVN_REG_IMM (code, dreg, imm8, rot_amount);
3930         } else {
3931                 if (v7_supported) {
3932                         ARM_MOVW_REG_IMM (code, dreg, val & 0xffff);
3933                         if (val >> 16)
3934                                 ARM_MOVT_REG_IMM (code, dreg, (val >> 16) & 0xffff);
3935                         return code;
3936                 }
3937                 if (val & 0xFF) {
3938                         ARM_MOV_REG_IMM8 (code, dreg, (val & 0xFF));
3939                         if (val & 0xFF00) {
3940                                 ARM_ADD_REG_IMM (code, dreg, dreg, (val & 0xFF00) >> 8, 24);
3941                         }
3942                         if (val & 0xFF0000) {
3943                                 ARM_ADD_REG_IMM (code, dreg, dreg, (val & 0xFF0000) >> 16, 16);
3944                         }
3945                         if (val & 0xFF000000) {
3946                                 ARM_ADD_REG_IMM (code, dreg, dreg, (val & 0xFF000000) >> 24, 8);
3947                         }
3948                 } else if (val & 0xFF00) {
3949                         ARM_MOV_REG_IMM (code, dreg, (val & 0xFF00) >> 8, 24);
3950                         if (val & 0xFF0000) {
3951                                 ARM_ADD_REG_IMM (code, dreg, dreg, (val & 0xFF0000) >> 16, 16);
3952                         }
3953                         if (val & 0xFF000000) {
3954                                 ARM_ADD_REG_IMM (code, dreg, dreg, (val & 0xFF000000) >> 24, 8);
3955                         }
3956                 } else if (val & 0xFF0000) {
3957                         ARM_MOV_REG_IMM (code, dreg, (val & 0xFF0000) >> 16, 16);
3958                         if (val & 0xFF000000) {
3959                                 ARM_ADD_REG_IMM (code, dreg, dreg, (val & 0xFF000000) >> 24, 8);
3960                         }
3961                 }
3962                 //g_assert_not_reached ();
3963         }
3964         return code;
3965 }
3966
3967 gboolean
3968 mono_arm_thumb_supported (void)
3969 {
3970         return thumb_supported;
3971 }
3972
3973 #ifndef DISABLE_JIT
3974
3975 /*
3976  * emit_load_volatile_arguments:
3977  *
3978  *  Load volatile arguments from the stack to the original input registers.
3979  * Required before a tail call.
3980  */
3981 static guint8*
3982 emit_load_volatile_arguments (MonoCompile *cfg, guint8 *code)
3983 {
3984         MonoMethod *method = cfg->method;
3985         MonoMethodSignature *sig;
3986         MonoInst *inst;
3987         CallInfo *cinfo;
3988         guint32 i, pos;
3989
3990         /* FIXME: Generate intermediate code instead */
3991
3992         sig = mono_method_signature (method);
3993
3994         /* This is the opposite of the code in emit_prolog */
3995
3996         pos = 0;
3997
3998         cinfo = get_call_info (cfg->generic_sharing_context, NULL, sig);
3999
4000         if (cinfo->vtype_retaddr) {
4001                 ArgInfo *ainfo = &cinfo->ret;
4002                 inst = cfg->vret_addr;
4003                 g_assert (arm_is_imm12 (inst->inst_offset));
4004                 ARM_LDR_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4005         }
4006         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4007                 ArgInfo *ainfo = cinfo->args + i;
4008                 inst = cfg->args [pos];
4009                 
4010                 if (cfg->verbose_level > 2)
4011                         g_print ("Loading argument %d (type: %d)\n", i, ainfo->storage);
4012                 if (inst->opcode == OP_REGVAR) {
4013                         if (ainfo->storage == RegTypeGeneral)
4014                                 ARM_MOV_REG_REG (code, inst->dreg, ainfo->reg);
4015                         else if (ainfo->storage == RegTypeFP) {
4016                                 g_assert_not_reached ();
4017                         } else if (ainfo->storage == RegTypeBase) {
4018                                 // FIXME:
4019                                 NOT_IMPLEMENTED;
4020                                 /*
4021                                 if (arm_is_imm12 (prev_sp_offset + ainfo->offset)) {
4022                                         ARM_LDR_IMM (code, inst->dreg, ARMREG_SP, (prev_sp_offset + ainfo->offset));
4023                                 } else {
4024                                         code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
4025                                         ARM_LDR_REG_REG (code, inst->dreg, ARMREG_SP, ARMREG_IP);
4026                                 }
4027                                 */
4028                         } else
4029                                 g_assert_not_reached ();
4030                 } else {
4031                         if (ainfo->storage == RegTypeGeneral || ainfo->storage == RegTypeIRegPair) {
4032                                 switch (ainfo->size) {
4033                                 case 1:
4034                                 case 2:
4035                                         // FIXME:
4036                                         NOT_IMPLEMENTED;
4037                                         break;
4038                                 case 8:
4039                                         g_assert (arm_is_imm12 (inst->inst_offset));
4040                                         ARM_LDR_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4041                                         g_assert (arm_is_imm12 (inst->inst_offset + 4));
4042                                         ARM_LDR_IMM (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);
4043                                         break;
4044                                 default:
4045                                         if (arm_is_imm12 (inst->inst_offset)) {
4046                                                 ARM_LDR_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4047                                         } else {
4048                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
4049                                                 ARM_LDR_REG_REG (code, ainfo->reg, inst->inst_basereg, ARMREG_IP);
4050                                         }
4051                                         break;
4052                                 }
4053                         } else if (ainfo->storage == RegTypeBaseGen) {
4054                                 // FIXME:
4055                                 NOT_IMPLEMENTED;
4056                         } else if (ainfo->storage == RegTypeBase) {
4057                                 /* Nothing to do */
4058                         } else if (ainfo->storage == RegTypeFP) {
4059                                 g_assert_not_reached ();
4060                         } else if (ainfo->storage == RegTypeStructByVal) {
4061                                 int doffset = inst->inst_offset;
4062                                 int soffset = 0;
4063                                 int cur_reg;
4064                                 int size = 0;
4065                                 if (mono_class_from_mono_type (inst->inst_vtype))
4066                                         size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
4067                                 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
4068                                         if (arm_is_imm12 (doffset)) {
4069                                                 ARM_LDR_IMM (code, ainfo->reg + cur_reg, inst->inst_basereg, doffset);
4070                                         } else {
4071                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, doffset);
4072                                                 ARM_LDR_REG_REG (code, ainfo->reg + cur_reg, inst->inst_basereg, ARMREG_IP);
4073                                         }
4074                                         soffset += sizeof (gpointer);
4075                                         doffset += sizeof (gpointer);
4076                                 }
4077                                 if (ainfo->vtsize)
4078                                         // FIXME:
4079                                         NOT_IMPLEMENTED;
4080                         } else if (ainfo->storage == RegTypeStructByAddr) {
4081                         } else {
4082                                 // FIXME:
4083                                 NOT_IMPLEMENTED;
4084                         }
4085                 }
4086                 pos ++;
4087         }
4088
4089         g_free (cinfo);
4090
4091         return code;
4092 }
4093
4094 void
4095 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
4096 {
4097         MonoInst *ins;
4098         MonoCallInst *call;
4099         guint offset;
4100         guint8 *code = cfg->native_code + cfg->code_len;
4101         MonoInst *last_ins = NULL;
4102         guint last_offset = 0;
4103         int max_len, cpos;
4104         int imm8, rot_amount;
4105
4106         /* we don't align basic blocks of loops on arm */
4107
4108         if (cfg->verbose_level > 2)
4109                 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
4110
4111         cpos = bb->max_offset;
4112
4113         if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
4114                 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
4115                 //g_assert (!mono_compile_aot);
4116                 //cpos += 6;
4117                 //if (bb->cil_code)
4118                 //      cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
4119                 /* this is not thread save, but good enough */
4120                 /* fixme: howto handle overflows? */
4121                 //x86_inc_mem (code, &cov->data [bb->dfn].count); 
4122         }
4123
4124     if (mono_break_at_bb_method && mono_method_desc_full_match (mono_break_at_bb_method, cfg->method) && bb->block_num == mono_break_at_bb_bb_num) {
4125                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
4126                                                          (gpointer)"mono_break");
4127                 code = emit_call_seq (cfg, code);
4128         }
4129
4130         MONO_BB_FOR_EACH_INS (bb, ins) {
4131                 offset = code - cfg->native_code;
4132
4133                 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
4134
4135                 if (offset > (cfg->code_size - max_len - 16)) {
4136                         cfg->code_size *= 2;
4137                         cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4138                         code = cfg->native_code + offset;
4139                 }
4140         //      if (ins->cil_code)
4141         //              g_print ("cil code\n");
4142                 mono_debug_record_line_number (cfg, ins, offset);
4143
4144                 switch (ins->opcode) {
4145                 case OP_MEMORY_BARRIER:
4146                         if (v6_supported) {
4147                                 ARM_MOV_REG_IMM8 (code, ARMREG_R0, 0);
4148                                 ARM_MCR (code, 15, 0, ARMREG_R0, 7, 10, 5);
4149                         }
4150                         break;
4151                 case OP_TLS_GET:
4152 #ifdef HAVE_AEABI_READ_TP
4153                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
4154                                                                  (gpointer)"__aeabi_read_tp");
4155                         code = emit_call_seq (cfg, code);
4156
4157                         ARM_LDR_IMM (code, ins->dreg, ARMREG_R0, ins->inst_offset);
4158 #else
4159                         g_assert_not_reached ();
4160 #endif
4161                         break;
4162                 case OP_ATOMIC_EXCHANGE_I4:
4163                 case OP_ATOMIC_CAS_I4:
4164                 case OP_ATOMIC_ADD_I4: {
4165                         int tmpreg;
4166                         guint8 *buf [16];
4167
4168                         g_assert (v7_supported);
4169
4170                         /* Free up a reg */
4171                         if (ins->sreg1 != ARMREG_IP && ins->sreg2 != ARMREG_IP && ins->sreg3 != ARMREG_IP)
4172                                 tmpreg = ARMREG_IP;
4173                         else if (ins->sreg1 != ARMREG_R0 && ins->sreg2 != ARMREG_R0 && ins->sreg3 != ARMREG_R0)
4174                                 tmpreg = ARMREG_R0;
4175                         else if (ins->sreg1 != ARMREG_R1 && ins->sreg2 != ARMREG_R1 && ins->sreg3 != ARMREG_R1)
4176                                 tmpreg = ARMREG_R1;
4177                         else
4178                                 tmpreg = ARMREG_R2;
4179                         g_assert (cfg->arch.atomic_tmp_offset != -1);
4180                         ARM_STR_IMM (code, tmpreg, cfg->frame_reg, cfg->arch.atomic_tmp_offset);
4181
4182                         switch (ins->opcode) {
4183                         case OP_ATOMIC_EXCHANGE_I4:
4184                                 buf [0] = code;
4185                                 ARM_DMB (code, ARM_DMB_SY);
4186                                 ARM_LDREX_REG (code, ARMREG_LR, ins->sreg1);
4187                                 ARM_STREX_REG (code, tmpreg, ins->sreg2, ins->sreg1);
4188                                 ARM_CMP_REG_IMM (code, tmpreg, 0, 0);
4189                                 buf [1] = code;
4190                                 ARM_B_COND (code, ARMCOND_NE, 0);
4191                                 arm_patch (buf [1], buf [0]);
4192                                 break;
4193                         case OP_ATOMIC_CAS_I4:
4194                                 ARM_DMB (code, ARM_DMB_SY);
4195                                 buf [0] = code;
4196                                 ARM_LDREX_REG (code, ARMREG_LR, ins->sreg1);
4197                                 ARM_CMP_REG_REG (code, ARMREG_LR, ins->sreg3);
4198                                 buf [1] = code;
4199                                 ARM_B_COND (code, ARMCOND_NE, 0);
4200                                 ARM_STREX_REG (code, tmpreg, ins->sreg2, ins->sreg1);
4201                                 ARM_CMP_REG_IMM (code, tmpreg, 0, 0);
4202                                 buf [2] = code;
4203                                 ARM_B_COND (code, ARMCOND_NE, 0);
4204                                 arm_patch (buf [2], buf [0]);
4205                                 arm_patch (buf [1], code);
4206                                 break;
4207                         case OP_ATOMIC_ADD_I4:
4208                                 buf [0] = code;
4209                                 ARM_DMB (code, ARM_DMB_SY);
4210                                 ARM_LDREX_REG (code, ARMREG_LR, ins->sreg1);
4211                                 ARM_ADD_REG_REG (code, ARMREG_LR, ARMREG_LR, ins->sreg2);
4212                                 ARM_STREX_REG (code, tmpreg, ARMREG_LR, ins->sreg1);
4213                                 ARM_CMP_REG_IMM (code, tmpreg, 0, 0);
4214                                 buf [1] = code;
4215                                 ARM_B_COND (code, ARMCOND_NE, 0);
4216                                 arm_patch (buf [1], buf [0]);
4217                                 break;
4218                         default:
4219                                 g_assert_not_reached ();
4220                         }
4221
4222                         ARM_DMB (code, ARM_DMB_SY);
4223                         if (tmpreg != ins->dreg)
4224                                 ARM_LDR_IMM (code, tmpreg, cfg->frame_reg, cfg->arch.atomic_tmp_offset);
4225                         ARM_MOV_REG_REG (code, ins->dreg, ARMREG_LR);
4226                         break;
4227                 }
4228
4229                 /*case OP_BIGMUL:
4230                         ppc_mullw (code, ppc_r4, ins->sreg1, ins->sreg2);
4231                         ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
4232                         break;
4233                 case OP_BIGMUL_UN:
4234                         ppc_mullw (code, ppc_r4, ins->sreg1, ins->sreg2);
4235                         ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
4236                         break;*/
4237                 case OP_STOREI1_MEMBASE_IMM:
4238                         code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_imm & 0xFF);
4239                         g_assert (arm_is_imm12 (ins->inst_offset));
4240                         ARM_STRB_IMM (code, ARMREG_LR, ins->inst_destbasereg, ins->inst_offset);
4241                         break;
4242                 case OP_STOREI2_MEMBASE_IMM:
4243                         code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_imm & 0xFFFF);
4244                         g_assert (arm_is_imm8 (ins->inst_offset));
4245                         ARM_STRH_IMM (code, ARMREG_LR, ins->inst_destbasereg, ins->inst_offset);
4246                         break;
4247                 case OP_STORE_MEMBASE_IMM:
4248                 case OP_STOREI4_MEMBASE_IMM:
4249                         code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_imm);
4250                         g_assert (arm_is_imm12 (ins->inst_offset));
4251                         ARM_STR_IMM (code, ARMREG_LR, ins->inst_destbasereg, ins->inst_offset);
4252                         break;
4253                 case OP_STOREI1_MEMBASE_REG:
4254                         g_assert (arm_is_imm12 (ins->inst_offset));
4255                         ARM_STRB_IMM (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4256                         break;
4257                 case OP_STOREI2_MEMBASE_REG:
4258                         g_assert (arm_is_imm8 (ins->inst_offset));
4259                         ARM_STRH_IMM (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4260                         break;
4261                 case OP_STORE_MEMBASE_REG:
4262                 case OP_STOREI4_MEMBASE_REG:
4263                         /* this case is special, since it happens for spill code after lowering has been called */
4264                         if (arm_is_imm12 (ins->inst_offset)) {
4265                                 ARM_STR_IMM (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4266                         } else {
4267                                 code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_offset);
4268                                 ARM_STR_REG_REG (code, ins->sreg1, ins->inst_destbasereg, ARMREG_LR);
4269                         }
4270                         break;
4271                 case OP_STOREI1_MEMINDEX:
4272                         ARM_STRB_REG_REG (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4273                         break;
4274                 case OP_STOREI2_MEMINDEX:
4275                         ARM_STRH_REG_REG (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4276                         break;
4277                 case OP_STORE_MEMINDEX:
4278                 case OP_STOREI4_MEMINDEX:
4279                         ARM_STR_REG_REG (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4280                         break;
4281                 case OP_LOADU4_MEM:
4282                         g_assert_not_reached ();
4283                         break;
4284                 case OP_LOAD_MEMINDEX:
4285                 case OP_LOADI4_MEMINDEX:
4286                 case OP_LOADU4_MEMINDEX:
4287                         ARM_LDR_REG_REG (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4288                         break;
4289                 case OP_LOADI1_MEMINDEX:
4290                         ARM_LDRSB_REG_REG (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4291                         break;
4292                 case OP_LOADU1_MEMINDEX:
4293                         ARM_LDRB_REG_REG (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4294                         break;
4295                 case OP_LOADI2_MEMINDEX:
4296                         ARM_LDRSH_REG_REG (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4297                         break;
4298                 case OP_LOADU2_MEMINDEX:
4299                         ARM_LDRH_REG_REG (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4300                         break;
4301                 case OP_LOAD_MEMBASE:
4302                 case OP_LOADI4_MEMBASE:
4303                 case OP_LOADU4_MEMBASE:
4304                         /* this case is special, since it happens for spill code after lowering has been called */
4305                         if (arm_is_imm12 (ins->inst_offset)) {
4306                                 ARM_LDR_IMM (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4307                         } else {
4308                                 code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_offset);
4309                                 ARM_LDR_REG_REG (code, ins->dreg, ins->inst_basereg, ARMREG_LR);
4310                         }
4311                         break;
4312                 case OP_LOADI1_MEMBASE:
4313                         g_assert (arm_is_imm8 (ins->inst_offset));
4314                         ARM_LDRSB_IMM (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4315                         break;
4316                 case OP_LOADU1_MEMBASE:
4317                         g_assert (arm_is_imm12 (ins->inst_offset));
4318                         ARM_LDRB_IMM (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4319                         break;
4320                 case OP_LOADU2_MEMBASE:
4321                         g_assert (arm_is_imm8 (ins->inst_offset));
4322                         ARM_LDRH_IMM (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4323                         break;
4324                 case OP_LOADI2_MEMBASE:
4325                         g_assert (arm_is_imm8 (ins->inst_offset));
4326                         ARM_LDRSH_IMM (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4327                         break;
4328                 case OP_ICONV_TO_I1:
4329                         ARM_SHL_IMM (code, ins->dreg, ins->sreg1, 24);
4330                         ARM_SAR_IMM (code, ins->dreg, ins->dreg, 24);
4331                         break;
4332                 case OP_ICONV_TO_I2:
4333                         ARM_SHL_IMM (code, ins->dreg, ins->sreg1, 16);
4334                         ARM_SAR_IMM (code, ins->dreg, ins->dreg, 16);
4335                         break;
4336                 case OP_ICONV_TO_U1:
4337                         ARM_AND_REG_IMM8 (code, ins->dreg, ins->sreg1, 0xff);
4338                         break;
4339                 case OP_ICONV_TO_U2:
4340                         ARM_SHL_IMM (code, ins->dreg, ins->sreg1, 16);
4341                         ARM_SHR_IMM (code, ins->dreg, ins->dreg, 16);
4342                         break;
4343                 case OP_COMPARE:
4344                 case OP_ICOMPARE:
4345                         ARM_CMP_REG_REG (code, ins->sreg1, ins->sreg2);
4346                         break;
4347                 case OP_COMPARE_IMM:
4348                 case OP_ICOMPARE_IMM:
4349                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
4350                         g_assert (imm8 >= 0);
4351                         ARM_CMP_REG_IMM (code, ins->sreg1, imm8, rot_amount);
4352                         break;
4353                 case OP_BREAK:
4354                         /*
4355                          * gdb does not like encountering the hw breakpoint ins in the debugged code. 
4356                          * So instead of emitting a trap, we emit a call a C function and place a 
4357                          * breakpoint there.
4358                          */
4359                         //*(int*)code = 0xef9f0001;
4360                         //code += 4;
4361                         //ARM_DBRK (code);
4362                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
4363                                                                  (gpointer)"mono_break");
4364                         code = emit_call_seq (cfg, code);
4365                         break;
4366                 case OP_RELAXED_NOP:
4367                         ARM_NOP (code);
4368                         break;
4369                 case OP_NOP:
4370                 case OP_DUMMY_USE:
4371                 case OP_DUMMY_STORE:
4372                 case OP_DUMMY_ICONST:
4373                 case OP_DUMMY_R8CONST:
4374                 case OP_NOT_REACHED:
4375                 case OP_NOT_NULL:
4376                         break;
4377                 case OP_SEQ_POINT: {
4378                         int i;
4379                         MonoInst *info_var = cfg->arch.seq_point_info_var;
4380                         MonoInst *ss_trigger_page_var = cfg->arch.ss_trigger_page_var;
4381                         MonoInst *ss_read_var = cfg->arch.seq_point_read_var;
4382                         MonoInst *ss_method_var = cfg->arch.seq_point_ss_method_var;
4383                         MonoInst *bp_method_var = cfg->arch.seq_point_bp_method_var;
4384                         MonoInst *var;
4385                         int dreg = ARMREG_LR;
4386
4387                         if (cfg->soft_breakpoints) {
4388                                 g_assert (!cfg->compile_aot);
4389                         }
4390
4391                         /*
4392                          * For AOT, we use one got slot per method, which will point to a
4393                          * SeqPointInfo structure, containing all the information required
4394                          * by the code below.
4395                          */
4396                         if (cfg->compile_aot) {
4397                                 g_assert (info_var);
4398                                 g_assert (info_var->opcode == OP_REGOFFSET);
4399                                 g_assert (arm_is_imm12 (info_var->inst_offset));
4400                         }
4401
4402                         if (!cfg->soft_breakpoints) {
4403                                 /*
4404                                  * Read from the single stepping trigger page. This will cause a
4405                                  * SIGSEGV when single stepping is enabled.
4406                                  * We do this _before_ the breakpoint, so single stepping after
4407                                  * a breakpoint is hit will step to the next IL offset.
4408                                  */
4409                                 g_assert (((guint64)(gsize)ss_trigger_page >> 32) == 0);
4410                         }
4411
4412                         if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
4413                                 if (cfg->soft_breakpoints) {
4414                                         /* Load the address of the sequence point trigger variable. */
4415                                         var = ss_read_var;
4416                                         g_assert (var);
4417                                         g_assert (var->opcode == OP_REGOFFSET);
4418                                         g_assert (arm_is_imm12 (var->inst_offset));
4419                                         ARM_LDR_IMM (code, dreg, var->inst_basereg, var->inst_offset);
4420
4421                                         /* Read the value and check whether it is non-zero. */
4422                                         ARM_LDR_IMM (code, dreg, dreg, 0);
4423                                         ARM_CMP_REG_IMM (code, dreg, 0, 0);
4424
4425                                         /* Load the address of the sequence point method. */
4426                                         var = ss_method_var;
4427                                         g_assert (var);
4428                                         g_assert (var->opcode == OP_REGOFFSET);
4429                                         g_assert (arm_is_imm12 (var->inst_offset));
4430                                         ARM_LDR_IMM (code, dreg, var->inst_basereg, var->inst_offset);
4431
4432                                         /* Call it conditionally. */
4433                                         ARM_BLX_REG_COND (code, ARMCOND_NE, dreg);
4434                                 } else {
4435                                         if (cfg->compile_aot) {
4436                                                 /* Load the trigger page addr from the variable initialized in the prolog */
4437                                                 var = ss_trigger_page_var;
4438                                                 g_assert (var);
4439                                                 g_assert (var->opcode == OP_REGOFFSET);
4440                                                 g_assert (arm_is_imm12 (var->inst_offset));
4441                                                 ARM_LDR_IMM (code, dreg, var->inst_basereg, var->inst_offset);
4442                                         } else {
4443 #ifdef USE_JUMP_TABLES
4444                                                 gpointer *jte = mono_jumptable_add_entry ();
4445                                                 code = mono_arm_load_jumptable_entry (code, jte, dreg);
4446                                                 jte [0] = ss_trigger_page;
4447 #else
4448                                                 ARM_LDR_IMM (code, dreg, ARMREG_PC, 0);
4449                                                 ARM_B (code, 0);
4450                                                 *(int*)code = (int)ss_trigger_page;
4451                                                 code += 4;
4452 #endif
4453                                         }
4454                                         ARM_LDR_IMM (code, dreg, dreg, 0);
4455                                 }
4456                         }
4457
4458                         mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
4459
4460                         if (cfg->soft_breakpoints) {
4461                                 /* Load the address of the breakpoint method into ip. */
4462                                 var = bp_method_var;
4463                                 g_assert (var);
4464                                 g_assert (var->opcode == OP_REGOFFSET);
4465                                 g_assert (arm_is_imm12 (var->inst_offset));
4466                                 ARM_LDR_IMM (code, dreg, var->inst_basereg, var->inst_offset);
4467
4468                                 /*
4469                                  * A placeholder for a possible breakpoint inserted by
4470                                  * mono_arch_set_breakpoint ().
4471                                  */
4472                                 ARM_NOP (code);
4473                         } else if (cfg->compile_aot) {
4474                                 guint32 offset = code - cfg->native_code;
4475                                 guint32 val;
4476
4477                                 ARM_LDR_IMM (code, dreg, info_var->inst_basereg, info_var->inst_offset);
4478                                 /* Add the offset */
4479                                 val = ((offset / 4) * sizeof (guint8*)) + MONO_STRUCT_OFFSET (SeqPointInfo, bp_addrs);
4480                                 /* Load the info->bp_addrs [offset], which is either 0 or the address of a trigger page */
4481                                 if (arm_is_imm12 ((int)val)) {
4482                                         ARM_LDR_IMM (code, dreg, dreg, val);
4483                                 } else {
4484                                         ARM_ADD_REG_IMM (code, dreg, dreg, (val & 0xFF), 0);
4485                                         if (val & 0xFF00)
4486                                                 ARM_ADD_REG_IMM (code, dreg, dreg, (val & 0xFF00) >> 8, 24);
4487                                         if (val & 0xFF0000)
4488                                                 ARM_ADD_REG_IMM (code, dreg, dreg, (val & 0xFF0000) >> 16, 16);
4489                                         g_assert (!(val & 0xFF000000));
4490
4491                                         ARM_LDR_IMM (code, dreg, dreg, 0);
4492                                 }
4493                                 /* What is faster, a branch or a load ? */
4494                                 ARM_CMP_REG_IMM (code, dreg, 0, 0);
4495                                 /* The breakpoint instruction */
4496                                 ARM_LDR_IMM_COND (code, dreg, dreg, 0, ARMCOND_NE);
4497                         } else {
4498                                 /* 
4499                                  * A placeholder for a possible breakpoint inserted by
4500                                  * mono_arch_set_breakpoint ().
4501                                  */
4502                                 for (i = 0; i < 4; ++i)
4503                                         ARM_NOP (code);
4504                         }
4505                         break;
4506                 }
4507                 case OP_ADDCC:
4508                 case OP_IADDCC:
4509                         ARM_ADDS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
4510                         break;
4511                 case OP_IADD:
4512                         ARM_ADD_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
4513                         break;
4514                 case OP_ADC:
4515                 case OP_IADC:
4516                         ARM_ADCS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
4517                         break;
4518                 case OP_ADDCC_IMM:
4519                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
4520                         g_assert (imm8 >= 0);
4521                         ARM_ADDS_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
4522                         break;
4523                 case OP_ADD_IMM:
4524                 case OP_IADD_IMM:
4525                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
4526                         g_assert (imm8 >= 0);
4527                         ARM_ADD_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
4528                         break;
4529                 case OP_ADC_IMM:
4530                 case OP_IADC_IMM:
4531                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
4532                         g_assert (imm8 >= 0);
4533                         ARM_ADCS_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
4534                         break;
4535                 case OP_IADD_OVF:
4536                         ARM_ADD_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
4537                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
4538                         break;
4539                 case OP_IADD_OVF_UN:
4540                         ARM_ADD_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
4541                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
4542                         break;
4543                 case OP_ISUB_OVF:
4544                         ARM_SUB_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
4545                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
4546                         break;
4547                 case OP_ISUB_OVF_UN:
4548                         ARM_SUB_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
4549                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
4550                         break;
4551                 case OP_ADD_OVF_CARRY:
4552                         ARM_ADCS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
4553                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
4554                         break;
4555                 case OP_ADD_OVF_UN_CARRY:
4556                         ARM_ADCS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
4557                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
4558                         break;
4559                 case OP_SUB_OVF_CARRY:
4560                         ARM_SBCS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
4561                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
4562                         break;
4563                 case OP_SUB_OVF_UN_CARRY:
4564                         ARM_SBCS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
4565                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
4566                         break;
4567                 case OP_SUBCC:
4568                 case OP_ISUBCC:
4569                         ARM_SUBS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
4570                         break;
4571                 case OP_SUBCC_IMM:
4572                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
4573                         g_assert (imm8 >= 0);
4574                         ARM_SUBS_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
4575                         break;
4576                 case OP_ISUB:
4577                         ARM_SUB_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
4578                         break;
4579                 case OP_SBB:
4580                 case OP_ISBB:
4581                         ARM_SBCS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
4582                         break;
4583                 case OP_SUB_IMM:
4584                 case OP_ISUB_IMM:
4585                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
4586                         g_assert (imm8 >= 0);
4587                         ARM_SUB_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
4588                         break;
4589                 case OP_SBB_IMM:
4590                 case OP_ISBB_IMM:
4591                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
4592                         g_assert (imm8 >= 0);
4593                         ARM_SBCS_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
4594                         break;
4595                 case OP_ARM_RSBS_IMM:
4596                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
4597                         g_assert (imm8 >= 0);
4598                         ARM_RSBS_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
4599                         break;
4600                 case OP_ARM_RSC_IMM:
4601                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
4602                         g_assert (imm8 >= 0);
4603                         ARM_RSC_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
4604                         break;
4605                 case OP_IAND:
4606                         ARM_AND_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
4607                         break;
4608                 case OP_AND_IMM:
4609                 case OP_IAND_IMM:
4610                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
4611                         g_assert (imm8 >= 0);
4612                         ARM_AND_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
4613                         break;
4614                 case OP_IDIV:
4615                         g_assert (v7s_supported);
4616                         ARM_SDIV (code, ins->dreg, ins->sreg1, ins->sreg2);
4617                         break;
4618                 case OP_IDIV_UN:
4619                         g_assert (v7s_supported);
4620                         ARM_UDIV (code, ins->dreg, ins->sreg1, ins->sreg2);
4621                         break;
4622                 case OP_IREM:
4623                         g_assert (v7s_supported);
4624                         ARM_SDIV (code, ARMREG_LR, ins->sreg1, ins->sreg2);
4625                         ARM_MLS (code, ins->dreg, ARMREG_LR, ins->sreg2, ins->sreg1);
4626                         break;
4627                 case OP_IREM_UN:
4628                         g_assert (v7s_supported);
4629                         ARM_UDIV (code, ARMREG_LR, ins->sreg1, ins->sreg2);
4630                         ARM_MLS (code, ins->dreg, ARMREG_LR, ins->sreg2, ins->sreg1);
4631                         break;
4632                 case OP_DIV_IMM:
4633                 case OP_REM_IMM:
4634                         g_assert_not_reached ();
4635                 case OP_IOR:
4636                         ARM_ORR_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
4637                         break;
4638                 case OP_OR_IMM:
4639                 case OP_IOR_IMM:
4640                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
4641                         g_assert (imm8 >= 0);
4642                         ARM_ORR_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
4643                         break;
4644                 case OP_IXOR:
4645                         ARM_EOR_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
4646                         break;
4647                 case OP_XOR_IMM:
4648                 case OP_IXOR_IMM:
4649                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
4650                         g_assert (imm8 >= 0);
4651                         ARM_EOR_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
4652                         break;
4653                 case OP_ISHL:
4654                         ARM_SHL_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
4655                         break;
4656                 case OP_SHL_IMM:
4657                 case OP_ISHL_IMM:
4658                         if (ins->inst_imm)
4659                                 ARM_SHL_IMM (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4660                         else if (ins->dreg != ins->sreg1)
4661                                 ARM_MOV_REG_REG (code, ins->dreg, ins->sreg1);
4662                         break;
4663                 case OP_ISHR:
4664                         ARM_SAR_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
4665                         break;
4666                 case OP_SHR_IMM:
4667                 case OP_ISHR_IMM:
4668                         if (ins->inst_imm)
4669                                 ARM_SAR_IMM (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4670                         else if (ins->dreg != ins->sreg1)
4671                                 ARM_MOV_REG_REG (code, ins->dreg, ins->sreg1);
4672                         break;
4673                 case OP_SHR_UN_IMM:
4674                 case OP_ISHR_UN_IMM:
4675                         if (ins->inst_imm)
4676                                 ARM_SHR_IMM (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4677                         else if (ins->dreg != ins->sreg1)
4678                                 ARM_MOV_REG_REG (code, ins->dreg, ins->sreg1);
4679                         break;
4680                 case OP_ISHR_UN:
4681                         ARM_SHR_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
4682                         break;
4683                 case OP_INOT:
4684                         ARM_MVN_REG_REG (code, ins->dreg, ins->sreg1);
4685                         break;
4686                 case OP_INEG:
4687                         ARM_RSB_REG_IMM8 (code, ins->dreg, ins->sreg1, 0);
4688                         break;
4689                 case OP_IMUL:
4690                         if (ins->dreg == ins->sreg2)
4691                                 ARM_MUL_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
4692                         else
4693                                 ARM_MUL_REG_REG (code, ins->dreg, ins->sreg2, ins->sreg1);
4694                         break;
4695                 case OP_MUL_IMM:
4696                         g_assert_not_reached ();
4697                         break;
4698                 case OP_IMUL_OVF:
4699                         /* FIXME: handle ovf/ sreg2 != dreg */
4700                         ARM_MUL_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
4701                         /* FIXME: MUL doesn't set the C/O flags on ARM */
4702                         break;
4703                 case OP_IMUL_OVF_UN:
4704                         /* FIXME: handle ovf/ sreg2 != dreg */
4705                         ARM_MUL_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
4706                         /* FIXME: MUL doesn't set the C/O flags on ARM */
4707                         break;
4708                 case OP_ICONST:
4709                         code = mono_arm_emit_load_imm (code, ins->dreg, ins->inst_c0);
4710                         break;
4711                 case OP_AOTCONST:
4712                         /* Load the GOT offset */
4713                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
4714                         ARM_LDR_IMM (code, ins->dreg, ARMREG_PC, 0);
4715                         ARM_B (code, 0);
4716                         *(gpointer*)code = NULL;
4717                         code += 4;
4718                         /* Load the value from the GOT */
4719                         ARM_LDR_REG_REG (code, ins->dreg, ARMREG_PC, ins->dreg);
4720                         break;
4721                 case OP_OBJC_GET_SELECTOR:
4722                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_OBJC_SELECTOR_REF, ins->inst_p0);
4723                         ARM_LDR_IMM (code, ins->dreg, ARMREG_PC, 0);
4724                         ARM_B (code, 0);
4725                         *(gpointer*)code = NULL;
4726                         code += 4;
4727                         ARM_LDR_REG_REG (code, ins->dreg, ARMREG_PC, ins->dreg);
4728                         break;
4729                 case OP_ICONV_TO_I4:
4730                 case OP_ICONV_TO_U4:
4731                 case OP_MOVE:
4732                         if (ins->dreg != ins->sreg1)
4733                                 ARM_MOV_REG_REG (code, ins->dreg, ins->sreg1);
4734                         break;
4735                 case OP_SETLRET: {
4736                         int saved = ins->sreg2;
4737                         if (ins->sreg2 == ARM_LSW_REG) {
4738                                 ARM_MOV_REG_REG (code, ARMREG_LR, ins->sreg2);
4739                                 saved = ARMREG_LR;
4740                         }
4741                         if (ins->sreg1 != ARM_LSW_REG)
4742                                 ARM_MOV_REG_REG (code, ARM_LSW_REG, ins->sreg1);
4743                         if (saved != ARM_MSW_REG)
4744                                 ARM_MOV_REG_REG (code, ARM_MSW_REG, saved);
4745                         break;
4746                 }
4747                 case OP_FMOVE:
4748                         if (IS_VFP)
4749                                 ARM_CPYD (code, ins->dreg, ins->sreg1);
4750                         break;
4751                 case OP_FCONV_TO_R4:
4752                         if (IS_VFP) {
4753                                 ARM_CVTD (code, ins->dreg, ins->sreg1);
4754                                 ARM_CVTS (code, ins->dreg, ins->dreg);
4755                         }
4756                         break;
4757                 case OP_JMP:
4758                         /*
4759                          * Keep in sync with mono_arch_emit_epilog
4760                          */
4761                         g_assert (!cfg->method->save_lmf);
4762
4763                         code = emit_load_volatile_arguments (cfg, code);
4764
4765                         code = emit_big_add (code, ARMREG_SP, cfg->frame_reg, cfg->stack_usage);
4766                         if (iphone_abi) {
4767                                 if (cfg->used_int_regs)
4768                                         ARM_POP (code, cfg->used_int_regs);
4769                                 ARM_POP (code, (1 << ARMREG_R7) | (1 << ARMREG_LR));
4770                         } else {
4771                                 ARM_POP (code, cfg->used_int_regs | (1 << ARMREG_LR));
4772                         }
4773                         mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
4774                         if (cfg->compile_aot) {
4775                                 ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0);
4776                                 ARM_B (code, 0);
4777                                 *(gpointer*)code = NULL;
4778                                 code += 4;
4779                                 ARM_LDR_REG_REG (code, ARMREG_PC, ARMREG_PC, ARMREG_IP);
4780                         } else {
4781                                 code = mono_arm_patchable_b (code, ARMCOND_AL);
4782                         }
4783                         break;
4784                 case OP_TAILCALL: {
4785                         MonoCallInst *call = (MonoCallInst*)ins;
4786
4787                         /*
4788                          * The stack looks like the following:
4789                          * <caller argument area>
4790                          * <saved regs etc>
4791                          * <rest of frame>
4792                          * <callee argument area>
4793                          * Need to copy the arguments from the callee argument area to
4794                          * the caller argument area, and pop the frame.
4795                          */
4796                         if (call->stack_usage) {
4797                                 int i, prev_sp_offset = 0;
4798
4799                                 /* Compute size of saved registers restored below */
4800                                 if (iphone_abi)
4801                                         prev_sp_offset = 2 * 4;
4802                                 else
4803                                         prev_sp_offset = 1 * 4;
4804                                 for (i = 0; i < 16; ++i) {
4805                                         if (cfg->used_int_regs & (1 << i))
4806                                                 prev_sp_offset += 4;
4807                                 }
4808
4809                                 code = emit_big_add (code, ARMREG_IP, cfg->frame_reg, cfg->stack_usage + prev_sp_offset);
4810
4811                                 /* Copy arguments on the stack to our argument area */
4812                                 for (i = 0; i < call->stack_usage; i += sizeof (mgreg_t)) {
4813                                         ARM_LDR_IMM (code, ARMREG_LR, ARMREG_SP, i);
4814                                         ARM_STR_IMM (code, ARMREG_LR, ARMREG_IP, i);
4815                                 }
4816                         }
4817
4818                         /*
4819                          * Keep in sync with mono_arch_emit_epilog
4820                          */
4821                         g_assert (!cfg->method->save_lmf);
4822
4823                         code = emit_big_add (code, ARMREG_SP, cfg->frame_reg, cfg->stack_usage);
4824                         if (iphone_abi) {
4825                                 if (cfg->used_int_regs)
4826                                         ARM_POP (code, cfg->used_int_regs);
4827                                 ARM_POP (code, (1 << ARMREG_R7) | (1 << ARMREG_LR));
4828                         } else {
4829                                 ARM_POP (code, cfg->used_int_regs | (1 << ARMREG_LR));
4830                         }
4831
4832                         mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, call->method);
4833                         if (cfg->compile_aot) {
4834                                 ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0);
4835                                 ARM_B (code, 0);
4836                                 *(gpointer*)code = NULL;
4837                                 code += 4;
4838                                 ARM_LDR_REG_REG (code, ARMREG_PC, ARMREG_PC, ARMREG_IP);
4839                         } else {
4840                                 code = mono_arm_patchable_b (code, ARMCOND_AL);
4841                         }
4842                         break;
4843                 }
4844                 case OP_CHECK_THIS:
4845                         /* ensure ins->sreg1 is not NULL */
4846                         ARM_LDRB_IMM (code, ARMREG_LR, ins->sreg1, 0);
4847                         break;
4848                 case OP_ARGLIST: {
4849                         g_assert (cfg->sig_cookie < 128);
4850                         ARM_LDR_IMM (code, ARMREG_IP, cfg->frame_reg, cfg->sig_cookie);
4851                         ARM_STR_IMM (code, ARMREG_IP, ins->sreg1, 0);
4852                         break;
4853                 }
4854                 case OP_FCALL:
4855                 case OP_LCALL:
4856                 case OP_VCALL:
4857                 case OP_VCALL2:
4858                 case OP_VOIDCALL:
4859                 case OP_CALL:
4860                         call = (MonoCallInst*)ins;
4861
4862                         if (IS_HARD_FLOAT)
4863                                 code = emit_float_args (cfg, call, code, &max_len, &offset);
4864
4865                         if (ins->flags & MONO_INST_HAS_METHOD)
4866                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
4867                         else
4868                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
4869                         code = emit_call_seq (cfg, code);
4870                         ins->flags |= MONO_INST_GC_CALLSITE;
4871                         ins->backend.pc_offset = code - cfg->native_code;
4872                         code = emit_move_return_value (cfg, ins, code);
4873                         break;
4874                 case OP_FCALL_REG:
4875                 case OP_LCALL_REG:
4876                 case OP_VCALL_REG:
4877                 case OP_VCALL2_REG:
4878                 case OP_VOIDCALL_REG:
4879                 case OP_CALL_REG:
4880                         if (IS_HARD_FLOAT)
4881                                 code = emit_float_args (cfg, (MonoCallInst *)ins, code, &max_len, &offset);
4882
4883                         code = emit_call_reg (code, ins->sreg1);
4884                         ins->flags |= MONO_INST_GC_CALLSITE;
4885                         ins->backend.pc_offset = code - cfg->native_code;
4886                         code = emit_move_return_value (cfg, ins, code);
4887                         break;
4888                 case OP_FCALL_MEMBASE:
4889                 case OP_LCALL_MEMBASE:
4890                 case OP_VCALL_MEMBASE:
4891                 case OP_VCALL2_MEMBASE:
4892                 case OP_VOIDCALL_MEMBASE:
4893                 case OP_CALL_MEMBASE: {
4894                         gboolean imt_arg = FALSE;
4895
4896                         g_assert (ins->sreg1 != ARMREG_LR);
4897                         call = (MonoCallInst*)ins;
4898
4899                         if (IS_HARD_FLOAT)
4900                                 code = emit_float_args (cfg, call, code, &max_len, &offset);
4901
4902                         if (call->dynamic_imt_arg || call->method->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
4903                                 imt_arg = TRUE;
4904                         if (!arm_is_imm12 (ins->inst_offset))
4905                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, ins->inst_offset);
4906 #ifdef USE_JUMP_TABLES
4907 #define LR_BIAS 0
4908 #else
4909 #define LR_BIAS 4
4910 #endif
4911                         if (imt_arg)
4912                                 ARM_ADD_REG_IMM8 (code, ARMREG_LR, ARMREG_PC, LR_BIAS);
4913                         else
4914                                 ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC);
4915 #undef LR_BIAS
4916                         if (!arm_is_imm12 (ins->inst_offset))
4917                                 ARM_LDR_REG_REG (code, ARMREG_PC, ins->sreg1, ARMREG_IP);
4918                         else
4919                                 ARM_LDR_IMM (code, ARMREG_PC, ins->sreg1, ins->inst_offset);
4920                         if (imt_arg) {
4921                                 /* 
4922                                  * We can't embed the method in the code stream in PIC code, or
4923                                  * in gshared code.
4924                                  * Instead, we put it in V5 in code emitted by 
4925                                  * mono_arch_emit_imt_argument (), and embed NULL here to 
4926                                  * signal the IMT thunk that the value is in V5.
4927                                  */
4928 #ifdef USE_JUMP_TABLES
4929                                 /* In case of jumptables we always use value in V5. */
4930 #else
4931
4932                                 if (call->dynamic_imt_arg)
4933                                         *((gpointer*)code) = NULL;
4934                                 else
4935                                         *((gpointer*)code) = (gpointer)call->method;
4936                                 code += 4;
4937 #endif
4938                         }
4939                         ins->flags |= MONO_INST_GC_CALLSITE;
4940                         ins->backend.pc_offset = code - cfg->native_code;
4941                         code = emit_move_return_value (cfg, ins, code);
4942                         break;
4943                 }
4944                 case OP_LOCALLOC: {
4945                         /* keep alignment */
4946                         int alloca_waste = cfg->param_area;
4947                         alloca_waste += 7;
4948                         alloca_waste &= ~7;
4949                         /* round the size to 8 bytes */
4950                         ARM_ADD_REG_IMM8 (code, ins->dreg, ins->sreg1, 7);
4951                         ARM_BIC_REG_IMM8 (code, ins->dreg, ins->dreg, 7);
4952                         if (alloca_waste)
4953                                 ARM_ADD_REG_IMM8 (code, ins->dreg, ins->dreg, alloca_waste);
4954                         ARM_SUB_REG_REG (code, ARMREG_SP, ARMREG_SP, ins->dreg);
4955                         /* memzero the area: dreg holds the size, sp is the pointer */
4956                         if (ins->flags & MONO_INST_INIT) {
4957                                 guint8 *start_loop, *branch_to_cond;
4958                                 ARM_MOV_REG_IMM8 (code, ARMREG_LR, 0);
4959                                 branch_to_cond = code;
4960                                 ARM_B (code, 0);
4961                                 start_loop = code;
4962                                 ARM_STR_REG_REG (code, ARMREG_LR, ARMREG_SP, ins->dreg);
4963                                 arm_patch (branch_to_cond, code);
4964                                 /* decrement by 4 and set flags */
4965                                 ARM_SUBS_REG_IMM8 (code, ins->dreg, ins->dreg, sizeof (mgreg_t));
4966                                 ARM_B_COND (code, ARMCOND_GE, 0);
4967                                 arm_patch (code - 4, start_loop);
4968                         }
4969                         ARM_ADD_REG_IMM8 (code, ins->dreg, ARMREG_SP, alloca_waste);
4970                         break;
4971                 }
4972                 case OP_DYN_CALL: {
4973                         int i;
4974                         MonoInst *var = cfg->dyn_call_var;
4975
4976                         g_assert (var->opcode == OP_REGOFFSET);
4977                         g_assert (arm_is_imm12 (var->inst_offset));
4978
4979                         /* lr = args buffer filled by mono_arch_get_dyn_call_args () */
4980                         ARM_MOV_REG_REG( code, ARMREG_LR, ins->sreg1);
4981                         /* ip = ftn */
4982                         ARM_MOV_REG_REG( code, ARMREG_IP, ins->sreg2);
4983
4984                         /* Save args buffer */
4985                         ARM_STR_IMM (code, ARMREG_LR, var->inst_basereg, var->inst_offset);
4986
4987                         /* Set stack slots using R0 as scratch reg */
4988                         /* MONO_ARCH_DYN_CALL_PARAM_AREA gives the size of stack space available */
4989                         for (i = 0; i < DYN_CALL_STACK_ARGS; ++i) {
4990                                 ARM_LDR_IMM (code, ARMREG_R0, ARMREG_LR, (PARAM_REGS + i) * sizeof (mgreg_t));
4991                                 ARM_STR_IMM (code, ARMREG_R0, ARMREG_SP, i * sizeof (mgreg_t));
4992                         }
4993
4994                         /* Set argument registers */
4995                         for (i = 0; i < PARAM_REGS; ++i)
4996                                 ARM_LDR_IMM (code, i, ARMREG_LR, i * sizeof (mgreg_t));
4997
4998                         /* Make the call */
4999                         ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC);
5000                         ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
5001
5002                         /* Save result */
5003                         ARM_LDR_IMM (code, ARMREG_IP, var->inst_basereg, var->inst_offset);
5004                         ARM_STR_IMM (code, ARMREG_R0, ARMREG_IP, MONO_STRUCT_OFFSET (DynCallArgs, res)); 
5005                         ARM_STR_IMM (code, ARMREG_R1, ARMREG_IP, MONO_STRUCT_OFFSET (DynCallArgs, res2)); 
5006                         break;
5007                 }
5008                 case OP_THROW: {
5009                         if (ins->sreg1 != ARMREG_R0)
5010                                 ARM_MOV_REG_REG (code, ARMREG_R0, ins->sreg1);
5011                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
5012                                              (gpointer)"mono_arch_throw_exception");
5013                         code = emit_call_seq (cfg, code);
5014                         break;
5015                 }
5016                 case OP_RETHROW: {
5017                         if (ins->sreg1 != ARMREG_R0)
5018                                 ARM_MOV_REG_REG (code, ARMREG_R0, ins->sreg1);
5019                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
5020                                              (gpointer)"mono_arch_rethrow_exception");
5021                         code = emit_call_seq (cfg, code);
5022                         break;
5023                 }
5024                 case OP_START_HANDLER: {
5025                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
5026                         int i, rot_amount;
5027
5028                         /* Reserve a param area, see filter-stack.exe */
5029                         if (cfg->param_area) {
5030                                 if ((i = mono_arm_is_rotated_imm8 (cfg->param_area, &rot_amount)) >= 0) {
5031                                         ARM_SUB_REG_IMM (code, ARMREG_SP, ARMREG_SP, i, rot_amount);
5032                                 } else {
5033                                         code = mono_arm_emit_load_imm (code, ARMREG_IP, cfg->param_area);
5034                                         ARM_SUB_REG_REG (code, ARMREG_SP, ARMREG_SP, ARMREG_IP);
5035                                 }
5036                         }
5037
5038                         if (arm_is_imm12 (spvar->inst_offset)) {
5039                                 ARM_STR_IMM (code, ARMREG_LR, spvar->inst_basereg, spvar->inst_offset);
5040                         } else {
5041                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, spvar->inst_offset);
5042                                 ARM_STR_REG_REG (code, ARMREG_LR, spvar->inst_basereg, ARMREG_IP);
5043                         }
5044                         break;
5045                 }
5046                 case OP_ENDFILTER: {
5047                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
5048                         int i, rot_amount;
5049
5050                         /* Free the param area */
5051                         if (cfg->param_area) {
5052                                 if ((i = mono_arm_is_rotated_imm8 (cfg->param_area, &rot_amount)) >= 0) {
5053                                         ARM_ADD_REG_IMM (code, ARMREG_SP, ARMREG_SP, i, rot_amount);
5054                                 } else {
5055                                         code = mono_arm_emit_load_imm (code, ARMREG_IP, cfg->param_area);
5056                                         ARM_ADD_REG_REG (code, ARMREG_SP, ARMREG_SP, ARMREG_IP);
5057                                 }
5058                         }
5059
5060                         if (ins->sreg1 != ARMREG_R0)
5061                                 ARM_MOV_REG_REG (code, ARMREG_R0, ins->sreg1);
5062                         if (arm_is_imm12 (spvar->inst_offset)) {
5063                                 ARM_LDR_IMM (code, ARMREG_IP, spvar->inst_basereg, spvar->inst_offset);
5064                         } else {
5065                                 g_assert (ARMREG_IP != spvar->inst_basereg);
5066                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, spvar->inst_offset);
5067                                 ARM_LDR_REG_REG (code, ARMREG_IP, spvar->inst_basereg, ARMREG_IP);
5068                         }
5069                         ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
5070                         break;
5071                 }
5072                 case OP_ENDFINALLY: {
5073                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
5074                         int i, rot_amount;
5075
5076                         /* Free the param area */
5077                         if (cfg->param_area) {
5078                                 if ((i = mono_arm_is_rotated_imm8 (cfg->param_area, &rot_amount)) >= 0) {
5079                                         ARM_ADD_REG_IMM (code, ARMREG_SP, ARMREG_SP, i, rot_amount);
5080                                 } else {
5081                                         code = mono_arm_emit_load_imm (code, ARMREG_IP, cfg->param_area);
5082                                         ARM_ADD_REG_REG (code, ARMREG_SP, ARMREG_SP, ARMREG_IP);
5083                                 }
5084                         }
5085
5086                         if (arm_is_imm12 (spvar->inst_offset)) {
5087                                 ARM_LDR_IMM (code, ARMREG_IP, spvar->inst_basereg, spvar->inst_offset);
5088                         } else {
5089                                 g_assert (ARMREG_IP != spvar->inst_basereg);
5090                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, spvar->inst_offset);
5091                                 ARM_LDR_REG_REG (code, ARMREG_IP, spvar->inst_basereg, ARMREG_IP);
5092                         }
5093                         ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
5094                         break;
5095                 }
5096                 case OP_CALL_HANDLER: 
5097                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
5098                         code = mono_arm_patchable_bl (code, ARMCOND_AL);
5099                         mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
5100                         break;
5101                 case OP_LABEL:
5102                         ins->inst_c0 = code - cfg->native_code;
5103                         break;
5104                 case OP_BR:
5105                         /*if (ins->inst_target_bb->native_offset) {
5106                                 ARM_B (code, 0);
5107                                 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset); 
5108                         } else*/ {
5109                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
5110                                 code = mono_arm_patchable_b (code, ARMCOND_AL);
5111                         } 
5112                         break;
5113                 case OP_BR_REG:
5114                         ARM_MOV_REG_REG (code, ARMREG_PC, ins->sreg1);
5115                         break;
5116                 case OP_SWITCH:
5117                         /* 
5118                          * In the normal case we have:
5119                          *      ldr pc, [pc, ins->sreg1 << 2]
5120                          *      nop
5121                          * If aot, we have:
5122                          *      ldr lr, [pc, ins->sreg1 << 2]
5123                          *      add pc, pc, lr
5124                          * After follows the data.
5125                          * FIXME: add aot support.
5126                          */
5127                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_SWITCH, ins->inst_p0);
5128 #ifdef USE_JUMP_TABLES
5129                         {
5130                                 gpointer *jte = mono_jumptable_add_entries (GPOINTER_TO_INT (ins->klass));
5131                                 code = mono_arm_load_jumptable_entry_addr (code, jte, ARMREG_IP);
5132                                 ARM_LDR_REG_REG_SHIFT (code, ARMREG_PC, ARMREG_IP, ins->sreg1, ARMSHIFT_LSL, 2);
5133                         }
5134 #else
5135
5136                         max_len += 4 * GPOINTER_TO_INT (ins->klass);
5137                         if (offset + max_len > (cfg->code_size - 16)) {
5138                                 cfg->code_size += max_len;
5139                                 cfg->code_size *= 2;
5140                                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5141                                 code = cfg->native_code + offset;
5142                         }
5143                         ARM_LDR_REG_REG_SHIFT (code, ARMREG_PC, ARMREG_PC, ins->sreg1, ARMSHIFT_LSL, 2);
5144                         ARM_NOP (code);
5145                         code += 4 * GPOINTER_TO_INT (ins->klass);
5146 #endif
5147                         break;
5148                 case OP_CEQ:
5149                 case OP_ICEQ:
5150                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 0, ARMCOND_NE);
5151                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_EQ);
5152                         break;
5153                 case OP_CLT:
5154                 case OP_ICLT:
5155                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
5156                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_LT);
5157                         break;
5158                 case OP_CLT_UN:
5159                 case OP_ICLT_UN:
5160                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
5161                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_LO);
5162                         break;
5163                 case OP_CGT:
5164                 case OP_ICGT:
5165                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
5166                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_GT);
5167                         break;
5168                 case OP_CGT_UN:
5169                 case OP_ICGT_UN:
5170                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
5171                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_HI);
5172                         break;
5173                 case OP_ICNEQ:
5174                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_NE);
5175                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 0, ARMCOND_EQ);
5176                         break;
5177                 case OP_ICGE:
5178                         ARM_MOV_REG_IMM8 (code, ins->dreg, 1);
5179                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 0, ARMCOND_LT);
5180                         break;
5181                 case OP_ICLE:
5182                         ARM_MOV_REG_IMM8 (code, ins->dreg, 1);
5183                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 0, ARMCOND_GT);
5184                         break;
5185                 case OP_ICGE_UN:
5186                 case OP_ICLE_UN:
5187                         ARM_MOV_REG_IMM8 (code, ins->dreg, 1);
5188                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 0, ARMCOND_LO);
5189                         break;
5190                 case OP_COND_EXC_EQ:
5191                 case OP_COND_EXC_NE_UN:
5192                 case OP_COND_EXC_LT:
5193                 case OP_COND_EXC_LT_UN:
5194                 case OP_COND_EXC_GT:
5195                 case OP_COND_EXC_GT_UN:
5196                 case OP_COND_EXC_GE:
5197                 case OP_COND_EXC_GE_UN:
5198                 case OP_COND_EXC_LE:
5199                 case OP_COND_EXC_LE_UN:
5200                         EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
5201                         break;
5202                 case OP_COND_EXC_IEQ:
5203                 case OP_COND_EXC_INE_UN:
5204                 case OP_COND_EXC_ILT:
5205                 case OP_COND_EXC_ILT_UN:
5206                 case OP_COND_EXC_IGT:
5207                 case OP_COND_EXC_IGT_UN:
5208                 case OP_COND_EXC_IGE:
5209                 case OP_COND_EXC_IGE_UN:
5210                 case OP_COND_EXC_ILE:
5211                 case OP_COND_EXC_ILE_UN:
5212                         EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_IEQ, ins->inst_p1);
5213                         break;
5214                 case OP_COND_EXC_C:
5215                 case OP_COND_EXC_IC:
5216                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (ARMCOND_CS, ins->inst_p1);
5217                         break;
5218                 case OP_COND_EXC_OV:
5219                 case OP_COND_EXC_IOV:
5220                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (ARMCOND_VS, ins->inst_p1);
5221                         break;
5222                 case OP_COND_EXC_NC:
5223                 case OP_COND_EXC_INC:
5224                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (ARMCOND_CC, ins->inst_p1);
5225                         break;
5226                 case OP_COND_EXC_NO:
5227                 case OP_COND_EXC_INO:
5228                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (ARMCOND_VC, ins->inst_p1);
5229                         break;
5230                 case OP_IBEQ:
5231                 case OP_IBNE_UN:
5232                 case OP_IBLT:
5233                 case OP_IBLT_UN:
5234                 case OP_IBGT:
5235                 case OP_IBGT_UN:
5236                 case OP_IBGE:
5237                 case OP_IBGE_UN:
5238                 case OP_IBLE:
5239                 case OP_IBLE_UN:
5240                         EMIT_COND_BRANCH (ins, ins->opcode - OP_IBEQ);
5241                         break;
5242
5243                 /* floating point opcodes */
5244                 case OP_R8CONST:
5245                         if (cfg->compile_aot) {
5246                                 ARM_FLDD (code, ins->dreg, ARMREG_PC, 0);
5247                                 ARM_B (code, 1);
5248                                 *(guint32*)code = ((guint32*)(ins->inst_p0))[0];
5249                                 code += 4;
5250                                 *(guint32*)code = ((guint32*)(ins->inst_p0))[1];
5251                                 code += 4;
5252                         } else {
5253                                 /* FIXME: we can optimize the imm load by dealing with part of 
5254                                  * the displacement in LDFD (aligning to 512).
5255                                  */
5256                                 code = mono_arm_emit_load_imm (code, ARMREG_LR, (guint32)ins->inst_p0);
5257                                 ARM_FLDD (code, ins->dreg, ARMREG_LR, 0);
5258                         }
5259                         break;
5260                 case OP_R4CONST:
5261                         if (cfg->compile_aot) {
5262                                 ARM_FLDS (code, ins->dreg, ARMREG_PC, 0);
5263                                 ARM_B (code, 0);
5264                                 *(guint32*)code = ((guint32*)(ins->inst_p0))[0];
5265                                 code += 4;
5266                                 ARM_CVTS (code, ins->dreg, ins->dreg);
5267                         } else {
5268                                 code = mono_arm_emit_load_imm (code, ARMREG_LR, (guint32)ins->inst_p0);
5269                                 ARM_FLDS (code, ins->dreg, ARMREG_LR, 0);
5270                                 ARM_CVTS (code, ins->dreg, ins->dreg);
5271                         }
5272                         break;
5273                 case OP_STORER8_MEMBASE_REG:
5274                         /* This is generated by the local regalloc pass which runs after the lowering pass */
5275                         if (!arm_is_fpimm8 (ins->inst_offset)) {
5276                                 code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_offset);
5277                                 ARM_ADD_REG_REG (code, ARMREG_LR, ARMREG_LR, ins->inst_destbasereg);
5278                                 ARM_FSTD (code, ins->sreg1, ARMREG_LR, 0);
5279                         } else {
5280                                 ARM_FSTD (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
5281                         }
5282                         break;
5283                 case OP_LOADR8_MEMBASE:
5284                         /* This is generated by the local regalloc pass which runs after the lowering pass */
5285                         if (!arm_is_fpimm8 (ins->inst_offset)) {
5286                                 code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_offset);
5287                                 ARM_ADD_REG_REG (code, ARMREG_LR, ARMREG_LR, ins->inst_basereg);
5288                                 ARM_FLDD (code, ins->dreg, ARMREG_LR, 0);
5289                         } else {
5290                                 ARM_FLDD (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
5291                         }
5292                         break;
5293                 case OP_STORER4_MEMBASE_REG:
5294                         g_assert (arm_is_fpimm8 (ins->inst_offset));
5295                         code = mono_arm_emit_vfp_scratch_save (cfg, code, vfp_scratch1);
5296                         ARM_CVTD (code, vfp_scratch1, ins->sreg1);
5297                         ARM_FSTS (code, vfp_scratch1, ins->inst_destbasereg, ins->inst_offset);
5298                         code = mono_arm_emit_vfp_scratch_restore (cfg, code, vfp_scratch1);
5299                         break;
5300                 case OP_LOADR4_MEMBASE:
5301                         g_assert (arm_is_fpimm8 (ins->inst_offset));
5302                         code = mono_arm_emit_vfp_scratch_save (cfg, code, vfp_scratch1);
5303                         ARM_FLDS (code, vfp_scratch1, ins->inst_basereg, ins->inst_offset);
5304                         ARM_CVTS (code, ins->dreg, vfp_scratch1);
5305                         code = mono_arm_emit_vfp_scratch_restore (cfg, code, vfp_scratch1);
5306                         break;
5307                 case OP_ICONV_TO_R_UN: {
5308                         g_assert_not_reached ();
5309                         break;
5310                 }
5311                 case OP_ICONV_TO_R4:
5312                         code = mono_arm_emit_vfp_scratch_save (cfg, code, vfp_scratch1);
5313                         ARM_FMSR (code, vfp_scratch1, ins->sreg1);
5314                         ARM_FSITOS (code, vfp_scratch1, vfp_scratch1);
5315                         ARM_CVTS (code, ins->dreg, vfp_scratch1);
5316                         code = mono_arm_emit_vfp_scratch_restore (cfg, code, vfp_scratch1);
5317                         break;
5318                 case OP_ICONV_TO_R8:
5319                         code = mono_arm_emit_vfp_scratch_save (cfg, code, vfp_scratch1);
5320                         ARM_FMSR (code, vfp_scratch1, ins->sreg1);
5321                         ARM_FSITOD (code, ins->dreg, vfp_scratch1);
5322                         code = mono_arm_emit_vfp_scratch_restore (cfg, code, vfp_scratch1);
5323                         break;
5324
5325                 case OP_SETFRET:
5326                         if (mono_method_signature (cfg->method)->ret->type == MONO_TYPE_R4) {
5327                                 ARM_CVTD (code, ARM_VFP_F0, ins->sreg1);
5328
5329                                 if (!IS_HARD_FLOAT) {
5330                                         ARM_FMRS (code, ARMREG_R0, ARM_VFP_F0);
5331                                 }
5332                         } else {
5333                                 if (IS_HARD_FLOAT) {
5334                                         ARM_CPYD (code, ARM_VFP_D0, ins->sreg1);
5335                                 } else {
5336                                         ARM_FMRRD (code, ARMREG_R0, ARMREG_R1, ins->sreg1);
5337                                 }
5338                         }
5339                         break;
5340                 case OP_FCONV_TO_I1:
5341                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
5342                         break;
5343                 case OP_FCONV_TO_U1:
5344                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
5345                         break;
5346                 case OP_FCONV_TO_I2:
5347                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
5348                         break;
5349                 case OP_FCONV_TO_U2:
5350                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
5351                         break;
5352                 case OP_FCONV_TO_I4:
5353                 case OP_FCONV_TO_I:
5354                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
5355                         break;
5356                 case OP_FCONV_TO_U4:
5357                 case OP_FCONV_TO_U:
5358                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
5359                         break;
5360                 case OP_FCONV_TO_I8:
5361                 case OP_FCONV_TO_U8:
5362                         g_assert_not_reached ();
5363                         /* Implemented as helper calls */
5364                         break;
5365                 case OP_LCONV_TO_R_UN:
5366                         g_assert_not_reached ();
5367                         /* Implemented as helper calls */
5368                         break;
5369                 case OP_LCONV_TO_OVF_I4_2: {
5370                         guint8 *high_bit_not_set, *valid_negative, *invalid_negative, *valid_positive;
5371                         /* 
5372                          * Valid ints: 0xffffffff:8000000 to 00000000:0x7f000000
5373                          */
5374
5375                         ARM_CMP_REG_IMM8 (code, ins->sreg1, 0);
5376                         high_bit_not_set = code;
5377                         ARM_B_COND (code, ARMCOND_GE, 0); /*branch if bit 31 of the lower part is not set*/
5378
5379                         ARM_CMN_REG_IMM8 (code, ins->sreg2, 1); /*This have the same effect as CMP reg, 0xFFFFFFFF */
5380                         valid_negative = code;
5381                         ARM_B_COND (code, ARMCOND_EQ, 0); /*branch if upper part == 0xFFFFFFFF (lower part has bit 31 set) */
5382                         invalid_negative = code;
5383                         ARM_B_COND (code, ARMCOND_AL, 0);
5384                         
5385                         arm_patch (high_bit_not_set, code);
5386
5387                         ARM_CMP_REG_IMM8 (code, ins->sreg2, 0);
5388                         valid_positive = code;
5389                         ARM_B_COND (code, ARMCOND_EQ, 0); /*branch if upper part == 0 (lower part has bit 31 clear)*/
5390
5391                         arm_patch (invalid_negative, code);
5392                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (ARMCOND_AL, "OverflowException");
5393
5394                         arm_patch (valid_negative, code);
5395                         arm_patch (valid_positive, code);
5396
5397                         if (ins->dreg != ins->sreg1)
5398                                 ARM_MOV_REG_REG (code, ins->dreg, ins->sreg1);
5399                         break;
5400                 }
5401                 case OP_FADD:
5402                         ARM_VFP_ADDD (code, ins->dreg, ins->sreg1, ins->sreg2);
5403                         break;
5404                 case OP_FSUB:
5405                         ARM_VFP_SUBD (code, ins->dreg, ins->sreg1, ins->sreg2);
5406                         break;          
5407                 case OP_FMUL:
5408                         ARM_VFP_MULD (code, ins->dreg, ins->sreg1, ins->sreg2);
5409                         break;          
5410                 case OP_FDIV:
5411                         ARM_VFP_DIVD (code, ins->dreg, ins->sreg1, ins->sreg2);
5412                         break;          
5413                 case OP_FNEG:
5414                         ARM_NEGD (code, ins->dreg, ins->sreg1);
5415                         break;
5416                 case OP_FREM:
5417                         /* emulated */
5418                         g_assert_not_reached ();
5419                         break;
5420                 case OP_FCOMPARE:
5421                         if (IS_VFP) {
5422                                 ARM_CMPD (code, ins->sreg1, ins->sreg2);
5423                                 ARM_FMSTAT (code);
5424                         }
5425                         break;
5426                 case OP_FCEQ:
5427                         if (IS_VFP) {
5428                                 ARM_CMPD (code, ins->sreg1, ins->sreg2);
5429                                 ARM_FMSTAT (code);
5430                         }
5431                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 0, ARMCOND_NE);
5432                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_EQ);
5433                         break;
5434                 case OP_FCLT:
5435                         if (IS_VFP) {
5436                                 ARM_CMPD (code, ins->sreg1, ins->sreg2);
5437                                 ARM_FMSTAT (code);
5438                         }
5439                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
5440                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_MI);
5441                         break;
5442                 case OP_FCLT_UN:
5443                         if (IS_VFP) {
5444                                 ARM_CMPD (code, ins->sreg1, ins->sreg2);
5445                                 ARM_FMSTAT (code);
5446                         }
5447                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
5448                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_MI);
5449                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_VS);
5450                         break;
5451                 case OP_FCGT:
5452                         if (IS_VFP) {
5453                                 ARM_CMPD (code, ins->sreg2, ins->sreg1);
5454                                 ARM_FMSTAT (code);
5455                         }
5456                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
5457                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_MI);
5458                         break;
5459                 case OP_FCGT_UN:
5460                         if (IS_VFP) {
5461                                 ARM_CMPD (code, ins->sreg2, ins->sreg1);
5462                                 ARM_FMSTAT (code);
5463                         }
5464                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
5465                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_MI);
5466                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_VS);
5467                         break;
5468                 case OP_FCNEQ:
5469                         if (IS_VFP) {
5470                                 ARM_CMPD (code, ins->sreg1, ins->sreg2);
5471                                 ARM_FMSTAT (code);
5472                         }
5473                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_NE);
5474                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 0, ARMCOND_EQ);
5475                         break;
5476                 case OP_FCGE:
5477                         if (IS_VFP) {
5478                                 ARM_CMPD (code, ins->sreg1, ins->sreg2);
5479                                 ARM_FMSTAT (code);
5480                         }
5481                         ARM_MOV_REG_IMM8 (code, ins->dreg, 1);
5482                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 0, ARMCOND_MI);
5483                         break;
5484                 case OP_FCLE:
5485                         if (IS_VFP) {
5486                                 ARM_CMPD (code, ins->sreg2, ins->sreg1);
5487                                 ARM_FMSTAT (code);
5488                         }
5489                         ARM_MOV_REG_IMM8 (code, ins->dreg, 1);
5490                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 0, ARMCOND_MI);
5491                         break;
5492
5493                 /* ARM FPA flags table:
5494                  * N        Less than               ARMCOND_MI
5495                  * Z        Equal                   ARMCOND_EQ
5496                  * C        Greater Than or Equal   ARMCOND_CS
5497                  * V        Unordered               ARMCOND_VS
5498                  */
5499                 case OP_FBEQ:
5500                         EMIT_COND_BRANCH (ins, OP_IBEQ - OP_IBEQ);
5501                         break;
5502                 case OP_FBNE_UN:
5503                         EMIT_COND_BRANCH (ins, OP_IBNE_UN - OP_IBEQ);
5504                         break;
5505                 case OP_FBLT:
5506                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_MI); /* N set */
5507                         break;
5508                 case OP_FBLT_UN:
5509                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_VS); /* V set */
5510                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_MI); /* N set */
5511                         break;
5512                 case OP_FBGT:
5513                 case OP_FBGT_UN:
5514                 case OP_FBLE:
5515                 case OP_FBLE_UN:
5516                         g_assert_not_reached ();
5517                         break;
5518                 case OP_FBGE:
5519                         if (IS_VFP) {
5520                                 EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_GE);
5521                         } else {
5522                                 /* FPA requires EQ even thou the docs suggests that just CS is enough */
5523                                 EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_EQ);
5524                                 EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_CS);
5525                         }
5526                         break;
5527                 case OP_FBGE_UN:
5528                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_VS); /* V set */
5529                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_GE);
5530                         break;
5531
5532                 case OP_CKFINITE: {
5533                         if (IS_VFP) {
5534                                 code = mono_arm_emit_vfp_scratch_save (cfg, code, vfp_scratch1);
5535                                 code = mono_arm_emit_vfp_scratch_save (cfg, code, vfp_scratch2);
5536
5537 #ifdef USE_JUMP_TABLES
5538                                 {
5539                                         gpointer *jte = mono_jumptable_add_entries (2);
5540                                         jte [0] = GUINT_TO_POINTER (0xffffffff);
5541                                         jte [1] = GUINT_TO_POINTER (0x7fefffff);
5542                                         code = mono_arm_load_jumptable_entry_addr (code, jte, ARMREG_IP);
5543                                         ARM_FLDD (code, vfp_scratch1, ARMREG_IP, 0);
5544                                 }
5545 #else
5546                                 ARM_ABSD (code, vfp_scratch2, ins->sreg1);
5547                                 ARM_FLDD (code, vfp_scratch1, ARMREG_PC, 0);
5548                                 ARM_B (code, 1);
5549                                 *(guint32*)code = 0xffffffff;
5550                                 code += 4;
5551                                 *(guint32*)code = 0x7fefffff;
5552                                 code += 4;
5553 #endif
5554                                 ARM_CMPD (code, vfp_scratch2, vfp_scratch1);
5555                                 ARM_FMSTAT (code);
5556                                 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (ARMCOND_GT, "ArithmeticException");
5557                                 ARM_CMPD (code, ins->sreg1, ins->sreg1);
5558                                 ARM_FMSTAT (code);
5559                                 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (ARMCOND_VS, "ArithmeticException");
5560                                 ARM_CPYD (code, ins->dreg, ins->sreg1);
5561
5562                                 code = mono_arm_emit_vfp_scratch_restore (cfg, code, vfp_scratch1);
5563                                 code = mono_arm_emit_vfp_scratch_restore (cfg, code, vfp_scratch2);
5564                         }
5565                         break;
5566                 }
5567
5568                 case OP_GC_LIVENESS_DEF:
5569                 case OP_GC_LIVENESS_USE:
5570                 case OP_GC_PARAM_SLOT_LIVENESS_DEF:
5571                         ins->backend.pc_offset = code - cfg->native_code;
5572                         break;
5573                 case OP_GC_SPILL_SLOT_LIVENESS_DEF:
5574                         ins->backend.pc_offset = code - cfg->native_code;
5575                         bb->spill_slot_defs = g_slist_prepend_mempool (cfg->mempool, bb->spill_slot_defs, ins);
5576                         break;
5577
5578                 default:
5579                         g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
5580                         g_assert_not_reached ();
5581                 }
5582
5583                 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
5584                         g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
5585                                    mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
5586                         g_assert_not_reached ();
5587                 }
5588                
5589                 cpos += max_len;
5590
5591                 last_ins = ins;
5592                 last_offset = offset;
5593         }
5594
5595         cfg->code_len = code - cfg->native_code;
5596 }
5597
5598 #endif /* DISABLE_JIT */
5599
5600 #ifdef HAVE_AEABI_READ_TP
5601 void __aeabi_read_tp (void);
5602 #endif
5603
5604 void
5605 mono_arch_register_lowlevel_calls (void)
5606 {
5607         /* The signature doesn't matter */
5608         mono_register_jit_icall (mono_arm_throw_exception, "mono_arm_throw_exception", mono_create_icall_signature ("void"), TRUE);
5609         mono_register_jit_icall (mono_arm_throw_exception_by_token, "mono_arm_throw_exception_by_token", mono_create_icall_signature ("void"), TRUE);
5610
5611 #ifndef MONO_CROSS_COMPILE
5612 #ifdef HAVE_AEABI_READ_TP
5613         mono_register_jit_icall (__aeabi_read_tp, "__aeabi_read_tp", mono_create_icall_signature ("void"), TRUE);
5614 #endif
5615 #endif
5616 }
5617
5618 #define patch_lis_ori(ip,val) do {\
5619                 guint16 *__lis_ori = (guint16*)(ip);    \
5620                 __lis_ori [1] = (((guint32)(val)) >> 16) & 0xffff;      \
5621                 __lis_ori [3] = ((guint32)(val)) & 0xffff;      \
5622         } while (0)
5623
5624 void
5625 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, MonoCodeManager *dyn_code_mp, gboolean run_cctors)
5626 {
5627         MonoJumpInfo *patch_info;
5628         gboolean compile_aot = !run_cctors;
5629
5630         for (patch_info = ji; patch_info; patch_info = patch_info->next) {
5631                 unsigned char *ip = patch_info->ip.i + code;
5632                 const unsigned char *target;
5633
5634                 if (patch_info->type == MONO_PATCH_INFO_SWITCH && !compile_aot) {
5635 #ifdef USE_JUMP_TABLES
5636                         gpointer *jt = mono_jumptable_get_entry (ip);
5637 #else
5638                         gpointer *jt = (gpointer*)(ip + 8);
5639 #endif
5640                         int i;
5641                         /* jt is the inlined jump table, 2 instructions after ip
5642                          * In the normal case we store the absolute addresses,
5643                          * otherwise the displacements.
5644                          */
5645                         for (i = 0; i < patch_info->data.table->table_size; i++)
5646                                 jt [i] = code + (int)patch_info->data.table->table [i];
5647                         continue;
5648                 }
5649
5650                 if (compile_aot) {
5651                         switch (patch_info->type) {
5652                         case MONO_PATCH_INFO_BB:
5653                         case MONO_PATCH_INFO_LABEL:
5654                                 break;
5655                         default:
5656                                 /* No need to patch these */
5657                                 continue;
5658                         }
5659                 }
5660
5661                 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
5662
5663                 switch (patch_info->type) {
5664                 case MONO_PATCH_INFO_IP:
5665                         g_assert_not_reached ();
5666                         patch_lis_ori (ip, ip);
5667                         continue;
5668                 case MONO_PATCH_INFO_METHOD_REL:
5669                         g_assert_not_reached ();
5670                         *((gpointer *)(ip)) = code + patch_info->data.offset;
5671                         continue;
5672                 case MONO_PATCH_INFO_METHODCONST:
5673                 case MONO_PATCH_INFO_CLASS:
5674                 case MONO_PATCH_INFO_IMAGE:
5675                 case MONO_PATCH_INFO_FIELD:
5676                 case MONO_PATCH_INFO_VTABLE:
5677                 case MONO_PATCH_INFO_IID:
5678                 case MONO_PATCH_INFO_SFLDA:
5679                 case MONO_PATCH_INFO_LDSTR:
5680                 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
5681                 case MONO_PATCH_INFO_LDTOKEN:
5682                         g_assert_not_reached ();
5683                         /* from OP_AOTCONST : lis + ori */
5684                         patch_lis_ori (ip, target);
5685                         continue;
5686                 case MONO_PATCH_INFO_R4:
5687                 case MONO_PATCH_INFO_R8:
5688                         g_assert_not_reached ();
5689                         *((gconstpointer *)(ip + 2)) = patch_info->data.target;
5690                         continue;
5691                 case MONO_PATCH_INFO_EXC_NAME:
5692                         g_assert_not_reached ();
5693                         *((gconstpointer *)(ip + 1)) = patch_info->data.name;
5694                         continue;
5695                 case MONO_PATCH_INFO_NONE:
5696                 case MONO_PATCH_INFO_BB_OVF:
5697                 case MONO_PATCH_INFO_EXC_OVF:
5698                         /* everything is dealt with at epilog output time */
5699                         continue;
5700                 default:
5701                         break;
5702                 }
5703                 arm_patch_general (domain, ip, target, dyn_code_mp);
5704         }
5705 }
5706
5707 #ifndef DISABLE_JIT
5708
5709 /*
5710  * Stack frame layout:
5711  * 
5712  *   ------------------- fp
5713  *      MonoLMF structure or saved registers
5714  *   -------------------
5715  *      locals
5716  *   -------------------
5717  *      spilled regs
5718  *   -------------------
5719  *      optional 8 bytes for tracing
5720  *   -------------------
5721  *      param area             size is cfg->param_area
5722  *   ------------------- sp
5723  */
5724 guint8 *
5725 mono_arch_emit_prolog (MonoCompile *cfg)
5726 {
5727         MonoMethod *method = cfg->method;
5728         MonoBasicBlock *bb;
5729         MonoMethodSignature *sig;
5730         MonoInst *inst;
5731         int alloc_size, orig_alloc_size, pos, max_offset, i, rot_amount;
5732         guint8 *code;
5733         CallInfo *cinfo;
5734         int tracing = 0;
5735         int lmf_offset = 0;
5736         int prev_sp_offset, reg_offset;
5737
5738         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
5739                 tracing = 1;
5740
5741         sig = mono_method_signature (method);
5742         cfg->code_size = 256 + sig->param_count * 64;
5743         code = cfg->native_code = g_malloc (cfg->code_size);
5744
5745         mono_emit_unwind_op_def_cfa (cfg, code, ARMREG_SP, 0);
5746
5747         alloc_size = cfg->stack_offset;
5748         pos = 0;
5749         prev_sp_offset = 0;
5750
5751         if (iphone_abi) {
5752                 /* 
5753                  * The iphone uses R7 as the frame pointer, and it points at the saved
5754                  * r7+lr:
5755                  *         <lr>
5756                  * r7 ->   <r7>
5757                  *         <rest of frame>
5758                  * We can't use r7 as a frame pointer since it points into the middle of
5759                  * the frame, so we keep using our own frame pointer.
5760                  * FIXME: Optimize this.
5761                  */
5762                 ARM_PUSH (code, (1 << ARMREG_R7) | (1 << ARMREG_LR));
5763                 ARM_MOV_REG_REG (code, ARMREG_R7, ARMREG_SP);
5764                 prev_sp_offset += 8; /* r7 and lr */
5765                 mono_emit_unwind_op_def_cfa_offset (cfg, code, prev_sp_offset);
5766                 mono_emit_unwind_op_offset (cfg, code, ARMREG_R7, (- prev_sp_offset) + 0);
5767         }
5768
5769         if (!method->save_lmf) {
5770                 if (iphone_abi) {
5771                         /* No need to push LR again */
5772                         if (cfg->used_int_regs)
5773                                 ARM_PUSH (code, cfg->used_int_regs);
5774                 } else {
5775                         ARM_PUSH (code, cfg->used_int_regs | (1 << ARMREG_LR));
5776                         prev_sp_offset += 4;
5777                 }
5778                 for (i = 0; i < 16; ++i) {
5779                         if (cfg->used_int_regs & (1 << i))
5780                                 prev_sp_offset += 4;
5781                 }
5782                 mono_emit_unwind_op_def_cfa_offset (cfg, code, prev_sp_offset);
5783                 reg_offset = 0;
5784                 for (i = 0; i < 16; ++i) {
5785                         if ((cfg->used_int_regs & (1 << i))) {
5786                                 mono_emit_unwind_op_offset (cfg, code, i, (- prev_sp_offset) + reg_offset);
5787                                 mini_gc_set_slot_type_from_cfa (cfg, (- prev_sp_offset) + reg_offset, SLOT_NOREF);
5788                                 reg_offset += 4;
5789                         }
5790                 }
5791                 if (iphone_abi) {
5792                         mono_emit_unwind_op_offset (cfg, code, ARMREG_LR, -4);
5793                         mini_gc_set_slot_type_from_cfa (cfg, -4, SLOT_NOREF);
5794                 } else {
5795                         mono_emit_unwind_op_offset (cfg, code, ARMREG_LR, -4);
5796                         mini_gc_set_slot_type_from_cfa (cfg, -4, SLOT_NOREF);
5797                 }
5798         } else {
5799                 ARM_MOV_REG_REG (code, ARMREG_IP, ARMREG_SP);
5800                 ARM_PUSH (code, 0x5ff0);
5801                 prev_sp_offset += 4 * 10; /* all but r0-r3, sp and pc */
5802                 mono_emit_unwind_op_def_cfa_offset (cfg, code, prev_sp_offset);
5803                 reg_offset = 0;
5804                 for (i = 0; i < 16; ++i) {
5805                         if ((i > ARMREG_R3) && (i != ARMREG_SP) && (i != ARMREG_PC)) {
5806                                 /* The original r7 is saved at the start */
5807                                 if (!(iphone_abi && i == ARMREG_R7))
5808                                         mono_emit_unwind_op_offset (cfg, code, i, (- prev_sp_offset) + reg_offset);
5809                                 reg_offset += 4;
5810                         }
5811                 }
5812                 g_assert (reg_offset == 4 * 10);
5813                 pos += sizeof (MonoLMF) - (4 * 10);
5814                 lmf_offset = pos;
5815         }
5816         alloc_size += pos;
5817         orig_alloc_size = alloc_size;
5818         // align to MONO_ARCH_FRAME_ALIGNMENT bytes
5819         if (alloc_size & (MONO_ARCH_FRAME_ALIGNMENT - 1)) {
5820                 alloc_size += MONO_ARCH_FRAME_ALIGNMENT - 1;
5821                 alloc_size &= ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
5822         }
5823
5824         /* the stack used in the pushed regs */
5825         if (prev_sp_offset & 4)
5826                 alloc_size += 4;
5827         cfg->stack_usage = alloc_size;
5828         if (alloc_size) {
5829                 if ((i = mono_arm_is_rotated_imm8 (alloc_size, &rot_amount)) >= 0) {
5830                         ARM_SUB_REG_IMM (code, ARMREG_SP, ARMREG_SP, i, rot_amount);
5831                 } else {
5832                         code = mono_arm_emit_load_imm (code, ARMREG_IP, alloc_size);
5833                         ARM_SUB_REG_REG (code, ARMREG_SP, ARMREG_SP, ARMREG_IP);
5834                 }
5835                 mono_emit_unwind_op_def_cfa_offset (cfg, code, prev_sp_offset + alloc_size);
5836         }
5837         if (cfg->frame_reg != ARMREG_SP) {
5838                 ARM_MOV_REG_REG (code, cfg->frame_reg, ARMREG_SP);
5839                 mono_emit_unwind_op_def_cfa_reg (cfg, code, cfg->frame_reg);
5840         }
5841         //g_print ("prev_sp_offset: %d, alloc_size:%d\n", prev_sp_offset, alloc_size);
5842         prev_sp_offset += alloc_size;
5843
5844         for (i = 0; i < alloc_size - orig_alloc_size; i += 4)
5845                 mini_gc_set_slot_type_from_cfa (cfg, (- prev_sp_offset) + orig_alloc_size + i, SLOT_NOREF);
5846
5847         /* compute max_offset in order to use short forward jumps
5848          * we could skip do it on arm because the immediate displacement
5849          * for jumps is large enough, it may be useful later for constant pools
5850          */
5851         max_offset = 0;
5852         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
5853                 MonoInst *ins = bb->code;
5854                 bb->max_offset = max_offset;
5855
5856                 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
5857                         max_offset += 6; 
5858
5859                 MONO_BB_FOR_EACH_INS (bb, ins)
5860                         max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
5861         }
5862
5863         /* store runtime generic context */
5864         if (cfg->rgctx_var) {
5865                 MonoInst *ins = cfg->rgctx_var;
5866
5867                 g_assert (ins->opcode == OP_REGOFFSET);
5868
5869                 if (arm_is_imm12 (ins->inst_offset)) {
5870                         ARM_STR_IMM (code, MONO_ARCH_RGCTX_REG, ins->inst_basereg, ins->inst_offset);
5871                 } else {
5872                         code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_offset);
5873                         ARM_STR_REG_REG (code, MONO_ARCH_RGCTX_REG, ins->inst_basereg, ARMREG_LR);
5874                 }
5875         }
5876
5877         /* load arguments allocated to register from the stack */
5878         pos = 0;
5879
5880         cinfo = get_call_info (cfg->generic_sharing_context, NULL, sig);
5881
5882         if (cinfo->vtype_retaddr) {
5883                 ArgInfo *ainfo = &cinfo->ret;
5884                 inst = cfg->vret_addr;
5885                 g_assert (arm_is_imm12 (inst->inst_offset));
5886                 ARM_STR_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5887         }
5888
5889         if (sig->call_convention == MONO_CALL_VARARG) {
5890                 ArgInfo *cookie = &cinfo->sig_cookie;
5891
5892                 /* Save the sig cookie address */
5893                 g_assert (cookie->storage == RegTypeBase);
5894
5895                 g_assert (arm_is_imm12 (prev_sp_offset + cookie->offset));
5896                 g_assert (arm_is_imm12 (cfg->sig_cookie));
5897                 ARM_ADD_REG_IMM8 (code, ARMREG_IP, cfg->frame_reg, prev_sp_offset + cookie->offset);
5898                 ARM_STR_IMM (code, ARMREG_IP, cfg->frame_reg, cfg->sig_cookie);
5899         }
5900
5901         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
5902                 ArgInfo *ainfo = cinfo->args + i;
5903                 inst = cfg->args [pos];
5904                 
5905                 if (cfg->verbose_level > 2)
5906                         g_print ("Saving argument %d (type: %d)\n", i, ainfo->storage);
5907                 if (inst->opcode == OP_REGVAR) {
5908                         if (ainfo->storage == RegTypeGeneral)
5909                                 ARM_MOV_REG_REG (code, inst->dreg, ainfo->reg);
5910                         else if (ainfo->storage == RegTypeFP) {
5911                                 g_assert_not_reached ();
5912                         } else if (ainfo->storage == RegTypeBase) {
5913                                 if (arm_is_imm12 (prev_sp_offset + ainfo->offset)) {
5914                                         ARM_LDR_IMM (code, inst->dreg, ARMREG_SP, (prev_sp_offset + ainfo->offset));
5915                                 } else {
5916                                         code = mono_arm_emit_load_imm (code, ARMREG_IP, prev_sp_offset + ainfo->offset);
5917                                         ARM_LDR_REG_REG (code, inst->dreg, ARMREG_SP, ARMREG_IP);
5918                                 }
5919                         } else
5920                                 g_assert_not_reached ();
5921
5922                         if (cfg->verbose_level > 2)
5923                                 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
5924                 } else {
5925                         /* the argument should be put on the stack: FIXME handle size != word  */
5926                         if (ainfo->storage == RegTypeGeneral || ainfo->storage == RegTypeIRegPair || ainfo->storage == RegTypeGSharedVtInReg) {
5927                                 switch (ainfo->size) {
5928                                 case 1:
5929                                         if (arm_is_imm12 (inst->inst_offset))
5930                                                 ARM_STRB_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5931                                         else {
5932                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
5933                                                 ARM_STRB_REG_REG (code, ainfo->reg, inst->inst_basereg, ARMREG_IP);
5934                                         }
5935                                         break;
5936                                 case 2:
5937                                         if (arm_is_imm8 (inst->inst_offset)) {
5938                                                 ARM_STRH_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5939                                         } else {
5940                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
5941                                                 ARM_STRH_REG_REG (code, ainfo->reg, inst->inst_basereg, ARMREG_IP);
5942                                         }
5943                                         break;
5944                                 case 8:
5945                                         if (arm_is_imm12 (inst->inst_offset)) {
5946                                                 ARM_STR_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5947                                         } else {
5948                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
5949                                                 ARM_STR_REG_REG (code, ainfo->reg, inst->inst_basereg, ARMREG_IP);
5950                                         }
5951                                         if (arm_is_imm12 (inst->inst_offset + 4)) {
5952                                                 ARM_STR_IMM (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);
5953                                         } else {
5954                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset + 4);
5955                                                 ARM_STR_REG_REG (code, ainfo->reg + 1, inst->inst_basereg, ARMREG_IP);
5956                                         }
5957                                         break;
5958                                 default:
5959                                         if (arm_is_imm12 (inst->inst_offset)) {
5960                                                 ARM_STR_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5961                                         } else {
5962                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
5963                                                 ARM_STR_REG_REG (code, ainfo->reg, inst->inst_basereg, ARMREG_IP);
5964                                         }
5965                                         break;
5966                                 }
5967                         } else if (ainfo->storage == RegTypeBaseGen) {
5968                                 if (arm_is_imm12 (prev_sp_offset + ainfo->offset)) {
5969                                         ARM_LDR_IMM (code, ARMREG_LR, ARMREG_SP, (prev_sp_offset + ainfo->offset));
5970                                 } else {
5971                                         code = mono_arm_emit_load_imm (code, ARMREG_IP, prev_sp_offset + ainfo->offset);
5972                                         ARM_LDR_REG_REG (code, ARMREG_LR, ARMREG_SP, ARMREG_IP);
5973                                 }
5974                                 if (arm_is_imm12 (inst->inst_offset + 4)) {
5975                                         ARM_STR_IMM (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset + 4);
5976                                         ARM_STR_IMM (code, ARMREG_R3, inst->inst_basereg, inst->inst_offset);
5977                                 } else {
5978                                         code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset + 4);
5979                                         ARM_STR_REG_REG (code, ARMREG_LR, inst->inst_basereg, ARMREG_IP);
5980                                         code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
5981                                         ARM_STR_REG_REG (code, ARMREG_R3, inst->inst_basereg, ARMREG_IP);
5982                                 }
5983                         } else if (ainfo->storage == RegTypeBase || ainfo->storage == RegTypeGSharedVtOnStack) {
5984                                 if (arm_is_imm12 (prev_sp_offset + ainfo->offset)) {
5985                                         ARM_LDR_IMM (code, ARMREG_LR, ARMREG_SP, (prev_sp_offset + ainfo->offset));
5986                                 } else {
5987                                         code = mono_arm_emit_load_imm (code, ARMREG_IP, prev_sp_offset + ainfo->offset);
5988                                         ARM_LDR_REG_REG (code, ARMREG_LR, ARMREG_SP, ARMREG_IP);
5989                                 }
5990
5991                                 switch (ainfo->size) {
5992                                 case 1:
5993                                         if (arm_is_imm8 (inst->inst_offset)) {
5994                                                 ARM_STRB_IMM (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset);
5995                                         } else {
5996                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
5997                                                 ARM_STRB_REG_REG (code, ARMREG_LR, inst->inst_basereg, ARMREG_IP);
5998                                         }
5999                                         break;
6000                                 case 2:
6001                                         if (arm_is_imm8 (inst->inst_offset)) {
6002                                                 ARM_STRH_IMM (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset);
6003                                         } else {
6004                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
6005                                                 ARM_STRH_REG_REG (code, ARMREG_LR, inst->inst_basereg, ARMREG_IP);
6006                                         }
6007                                         break;
6008                                 case 8:
6009                                         if (arm_is_imm12 (inst->inst_offset)) {
6010                                                 ARM_STR_IMM (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset);
6011                                         } else {
6012                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
6013                                                 ARM_STR_REG_REG (code, ARMREG_LR, inst->inst_basereg, ARMREG_IP);
6014                                         }
6015                                         if (arm_is_imm12 (prev_sp_offset + ainfo->offset + 4)) {
6016                                                 ARM_LDR_IMM (code, ARMREG_LR, ARMREG_SP, (prev_sp_offset + ainfo->offset + 4));
6017                                         } else {
6018                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, prev_sp_offset + ainfo->offset + 4);
6019                                                 ARM_LDR_REG_REG (code, ARMREG_LR, ARMREG_SP, ARMREG_IP);
6020                                         }
6021                                         if (arm_is_imm12 (inst->inst_offset + 4)) {
6022                                                 ARM_STR_IMM (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset + 4);
6023                                         } else {
6024                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset + 4);
6025                                                 ARM_STR_REG_REG (code, ARMREG_LR, inst->inst_basereg, ARMREG_IP);
6026                                         }
6027                                         break;
6028                                 default:
6029                                         if (arm_is_imm12 (inst->inst_offset)) {
6030                                                 ARM_STR_IMM (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset);
6031                                         } else {
6032                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
6033                                                 ARM_STR_REG_REG (code, ARMREG_LR, inst->inst_basereg, ARMREG_IP);
6034                                         }
6035                                         break;
6036                                 }
6037                         } else if (ainfo->storage == RegTypeFP) {
6038                                 int imm8, rot_amount;
6039
6040                                 if ((imm8 = mono_arm_is_rotated_imm8 (inst->inst_offset, &rot_amount)) == -1) {
6041                                         code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
6042                                         ARM_ADD_REG_REG (code, ARMREG_IP, ARMREG_IP, inst->inst_basereg);
6043                                 } else
6044                                         ARM_ADD_REG_IMM (code, ARMREG_IP, inst->inst_basereg, imm8, rot_amount);
6045
6046                                 if (ainfo->size == 8)
6047                                         ARM_FSTD (code, ainfo->reg, ARMREG_IP, 0);
6048                                 else
6049                                         ARM_FSTS (code, ainfo->reg, ARMREG_IP, 0);
6050                         } else if (ainfo->storage == RegTypeStructByVal) {
6051                                 int doffset = inst->inst_offset;
6052                                 int soffset = 0;
6053                                 int cur_reg;
6054                                 int size = 0;
6055                                 size = mini_type_stack_size_full (cfg->generic_sharing_context, inst->inst_vtype, NULL, sig->pinvoke);
6056                                 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
6057                                         if (arm_is_imm12 (doffset)) {
6058                                                 ARM_STR_IMM (code, ainfo->reg + cur_reg, inst->inst_basereg, doffset);
6059                                         } else {
6060                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, doffset);
6061                                                 ARM_STR_REG_REG (code, ainfo->reg + cur_reg, inst->inst_basereg, ARMREG_IP);
6062                                         }
6063                                         soffset += sizeof (gpointer);
6064                                         doffset += sizeof (gpointer);
6065                                 }
6066                                 if (ainfo->vtsize) {
6067                                         /* FIXME: handle overrun! with struct sizes not multiple of 4 */
6068                                         //g_print ("emit_memcpy (prev_sp_ofs: %d, ainfo->offset: %d, soffset: %d)\n", prev_sp_offset, ainfo->offset, soffset);
6069                                         code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, doffset, ARMREG_SP, prev_sp_offset + ainfo->offset);
6070                                 }
6071                         } else if (ainfo->storage == RegTypeStructByAddr) {
6072                                 g_assert_not_reached ();
6073                                 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
6074                                 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
6075                         } else
6076                                 g_assert_not_reached ();
6077                 }
6078                 pos++;
6079         }
6080
6081         if (method->save_lmf)
6082                 code = emit_save_lmf (cfg, code, alloc_size - lmf_offset);
6083
6084         if (tracing)
6085                 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
6086
6087         if (cfg->arch.seq_point_info_var) {
6088                 MonoInst *ins = cfg->arch.seq_point_info_var;
6089
6090                 /* Initialize the variable from a GOT slot */
6091                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_SEQ_POINT_INFO, cfg->method);
6092 #ifdef USE_JUMP_TABLES
6093                 {
6094                         gpointer *jte = mono_jumptable_add_entry ();
6095                         code = mono_arm_load_jumptable_entry (code, jte, ARMREG_IP);
6096                         ARM_LDR_IMM (code, ARMREG_R0, ARMREG_IP, 0);
6097                 }
6098                 /** XXX: is it correct? */
6099 #else
6100                 ARM_LDR_IMM (code, ARMREG_R0, ARMREG_PC, 0);
6101                 ARM_B (code, 0);
6102                 *(gpointer*)code = NULL;
6103                 code += 4;
6104 #endif
6105                 ARM_LDR_REG_REG (code, ARMREG_R0, ARMREG_PC, ARMREG_R0);
6106
6107                 g_assert (ins->opcode == OP_REGOFFSET);
6108
6109                 if (arm_is_imm12 (ins->inst_offset)) {
6110                         ARM_STR_IMM (code, ARMREG_R0, ins->inst_basereg, ins->inst_offset);
6111                 } else {
6112                         code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_offset);
6113                         ARM_STR_REG_REG (code, ARMREG_R0, ins->inst_basereg, ARMREG_LR);
6114                 }
6115         }
6116
6117         /* Initialize ss_trigger_page_var */
6118         if (!cfg->soft_breakpoints) {
6119                 MonoInst *info_var = cfg->arch.seq_point_info_var;
6120                 MonoInst *ss_trigger_page_var = cfg->arch.ss_trigger_page_var;
6121                 int dreg = ARMREG_LR;
6122
6123                 if (info_var) {
6124                         g_assert (info_var->opcode == OP_REGOFFSET);
6125                         g_assert (arm_is_imm12 (info_var->inst_offset));
6126
6127                         ARM_LDR_IMM (code, dreg, info_var->inst_basereg, info_var->inst_offset);
6128                         /* Load the trigger page addr */
6129                         ARM_LDR_IMM (code, dreg, dreg, MONO_STRUCT_OFFSET (SeqPointInfo, ss_trigger_page));
6130                         ARM_STR_IMM (code, dreg, ss_trigger_page_var->inst_basereg, ss_trigger_page_var->inst_offset);
6131                 }
6132         }
6133
6134         if (cfg->arch.seq_point_read_var) {
6135                 MonoInst *read_ins = cfg->arch.seq_point_read_var;
6136                 MonoInst *ss_method_ins = cfg->arch.seq_point_ss_method_var;
6137                 MonoInst *bp_method_ins = cfg->arch.seq_point_bp_method_var;
6138 #ifdef USE_JUMP_TABLES
6139                 gpointer *jte;
6140 #endif
6141                 g_assert (read_ins->opcode == OP_REGOFFSET);
6142                 g_assert (arm_is_imm12 (read_ins->inst_offset));
6143                 g_assert (ss_method_ins->opcode == OP_REGOFFSET);
6144                 g_assert (arm_is_imm12 (ss_method_ins->inst_offset));
6145                 g_assert (bp_method_ins->opcode == OP_REGOFFSET);
6146                 g_assert (arm_is_imm12 (bp_method_ins->inst_offset));
6147
6148 #ifdef USE_JUMP_TABLES
6149                 jte = mono_jumptable_add_entries (3);
6150                 jte [0] = (gpointer)&ss_trigger_var;
6151                 jte [1] = single_step_func_wrapper;
6152                 jte [2] = breakpoint_func_wrapper;
6153                 code = mono_arm_load_jumptable_entry_addr (code, jte, ARMREG_LR);
6154 #else
6155                 ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC);
6156                 ARM_B (code, 2);
6157                 *(volatile int **)code = &ss_trigger_var;
6158                 code += 4;
6159                 *(gpointer*)code = single_step_func_wrapper;
6160                 code += 4;
6161                 *(gpointer*)code = breakpoint_func_wrapper;
6162                 code += 4;
6163 #endif
6164
6165                 ARM_LDR_IMM (code, ARMREG_IP, ARMREG_LR, 0);
6166                 ARM_STR_IMM (code, ARMREG_IP, read_ins->inst_basereg, read_ins->inst_offset);
6167                 ARM_LDR_IMM (code, ARMREG_IP, ARMREG_LR, 4);
6168                 ARM_STR_IMM (code, ARMREG_IP, ss_method_ins->inst_basereg, ss_method_ins->inst_offset);
6169                 ARM_LDR_IMM (code, ARMREG_IP, ARMREG_LR, 8);
6170                 ARM_STR_IMM (code, ARMREG_IP, bp_method_ins->inst_basereg, bp_method_ins->inst_offset);
6171         }
6172
6173         cfg->code_len = code - cfg->native_code;
6174         g_assert (cfg->code_len < cfg->code_size);
6175         g_free (cinfo);
6176
6177         return code;
6178 }
6179
6180 void
6181 mono_arch_emit_epilog (MonoCompile *cfg)
6182 {
6183         MonoMethod *method = cfg->method;
6184         int pos, i, rot_amount;
6185         int max_epilog_size = 16 + 20*4;
6186         guint8 *code;
6187         CallInfo *cinfo;
6188
6189         if (cfg->method->save_lmf)
6190                 max_epilog_size += 128;
6191         
6192         if (mono_jit_trace_calls != NULL)
6193                 max_epilog_size += 50;
6194
6195         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
6196                 max_epilog_size += 50;
6197
6198         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
6199                 cfg->code_size *= 2;
6200                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
6201                 cfg->stat_code_reallocs++;
6202         }
6203
6204         /*
6205          * Keep in sync with OP_JMP
6206          */
6207         code = cfg->native_code + cfg->code_len;
6208
6209         if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
6210                 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
6211         }
6212         pos = 0;
6213
6214         /* Load returned vtypes into registers if needed */
6215         cinfo = cfg->arch.cinfo;
6216         if (cinfo->ret.storage == RegTypeStructByVal) {
6217                 MonoInst *ins = cfg->ret;
6218
6219                 if (arm_is_imm12 (ins->inst_offset)) {
6220                         ARM_LDR_IMM (code, ARMREG_R0, ins->inst_basereg, ins->inst_offset);
6221                 } else {
6222                         code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_offset);
6223                         ARM_LDR_REG_REG (code, ARMREG_R0, ins->inst_basereg, ARMREG_LR);
6224                 }
6225         }
6226
6227         if (method->save_lmf) {
6228                 int lmf_offset, reg, sp_adj, regmask;
6229                 /* all but r0-r3, sp and pc */
6230                 pos += sizeof (MonoLMF) - (MONO_ARM_NUM_SAVED_REGS * sizeof (mgreg_t));
6231                 lmf_offset = pos;
6232
6233                 code = emit_restore_lmf (cfg, code, cfg->stack_usage - lmf_offset);
6234
6235                 /* This points to r4 inside MonoLMF->iregs */
6236                 sp_adj = (sizeof (MonoLMF) - MONO_ARM_NUM_SAVED_REGS * sizeof (mgreg_t));
6237                 reg = ARMREG_R4;
6238                 regmask = 0x9ff0; /* restore lr to pc */
6239                 /* Skip caller saved registers not used by the method */
6240                 while (!(cfg->used_int_regs & (1 << reg)) && reg < ARMREG_FP) {
6241                         regmask &= ~(1 << reg);
6242                         sp_adj += 4;
6243                         reg ++;
6244                 }
6245                 if (iphone_abi)
6246                         /* Restored later */
6247                         regmask &= ~(1 << ARMREG_PC);
6248                 /* point sp at the registers to restore: 10 is 14 -4, because we skip r0-r3 */
6249                 code = emit_big_add (code, ARMREG_SP, cfg->frame_reg, cfg->stack_usage - lmf_offset + sp_adj);
6250                 /* restore iregs */
6251                 ARM_POP (code, regmask); 
6252                 if (iphone_abi) {
6253                         /* Restore saved r7, restore LR to PC */
6254                         /* Skip lr from the lmf */
6255                         ARM_ADD_REG_IMM (code, ARMREG_SP, ARMREG_SP, sizeof (gpointer), 0);
6256                         ARM_POP (code, (1 << ARMREG_R7) | (1 << ARMREG_PC));
6257                 }
6258         } else {
6259                 if ((i = mono_arm_is_rotated_imm8 (cfg->stack_usage, &rot_amount)) >= 0) {
6260                         ARM_ADD_REG_IMM (code, ARMREG_SP, cfg->frame_reg, i, rot_amount);
6261                 } else {
6262                         code = mono_arm_emit_load_imm (code, ARMREG_IP, cfg->stack_usage);
6263                         ARM_ADD_REG_REG (code, ARMREG_SP, cfg->frame_reg, ARMREG_IP);
6264                 }
6265
6266                 if (iphone_abi) {
6267                         /* Restore saved gregs */
6268                         if (cfg->used_int_regs)
6269                                 ARM_POP (code, cfg->used_int_regs);
6270                         /* Restore saved r7, restore LR to PC */
6271                         ARM_POP (code, (1 << ARMREG_R7) | (1 << ARMREG_PC));
6272                 } else {
6273                         ARM_POP (code, cfg->used_int_regs | (1 << ARMREG_PC));
6274                 }
6275         }
6276
6277         cfg->code_len = code - cfg->native_code;
6278
6279         g_assert (cfg->code_len < cfg->code_size);
6280
6281 }
6282
6283 void
6284 mono_arch_emit_exceptions (MonoCompile *cfg)
6285 {
6286         MonoJumpInfo *patch_info;
6287         int i;
6288         guint8 *code;
6289         guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM];
6290         guint8 exc_throw_found [MONO_EXC_INTRINS_NUM];
6291         int max_epilog_size = 50;
6292
6293         for (i = 0; i < MONO_EXC_INTRINS_NUM; i++) {
6294                 exc_throw_pos [i] = NULL;
6295                 exc_throw_found [i] = 0;
6296         }
6297
6298         /* count the number of exception infos */
6299      
6300         /* 
6301          * make sure we have enough space for exceptions
6302          */
6303         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
6304                 if (patch_info->type == MONO_PATCH_INFO_EXC) {
6305                         i = mini_exception_id_by_name (patch_info->data.target);
6306                         if (!exc_throw_found [i]) {
6307                                 max_epilog_size += 32;
6308                                 exc_throw_found [i] = TRUE;
6309                         }
6310                 }
6311         }
6312
6313         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
6314                 cfg->code_size *= 2;
6315                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
6316                 cfg->stat_code_reallocs++;
6317         }
6318
6319         code = cfg->native_code + cfg->code_len;
6320
6321         /* add code to raise exceptions */
6322         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
6323                 switch (patch_info->type) {
6324                 case MONO_PATCH_INFO_EXC: {
6325                         MonoClass *exc_class;
6326                         unsigned char *ip = patch_info->ip.i + cfg->native_code;
6327
6328                         i = mini_exception_id_by_name (patch_info->data.target);
6329                         if (exc_throw_pos [i]) {
6330                                 arm_patch (ip, exc_throw_pos [i]);
6331                                 patch_info->type = MONO_PATCH_INFO_NONE;
6332                                 break;
6333                         } else {
6334                                 exc_throw_pos [i] = code;
6335                         }
6336                         arm_patch (ip, code);
6337
6338                         exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
6339                         g_assert (exc_class);
6340
6341                         ARM_MOV_REG_REG (code, ARMREG_R1, ARMREG_LR);
6342 #ifdef USE_JUMP_TABLES
6343                         {
6344                                 gpointer *jte = mono_jumptable_add_entries (2);
6345                                 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
6346                                 patch_info->data.name = "mono_arch_throw_corlib_exception";
6347                                 patch_info->ip.i = code - cfg->native_code;
6348                                 code = mono_arm_load_jumptable_entry_addr (code, jte, ARMREG_R0);
6349                                 ARM_LDR_IMM (code, ARMREG_IP, ARMREG_R0, 0);
6350                                 ARM_LDR_IMM (code, ARMREG_R0, ARMREG_R0, 4);
6351                                 ARM_BLX_REG (code, ARMREG_IP);
6352                                 jte [1] = GUINT_TO_POINTER (exc_class->type_token);
6353                         }
6354 #else
6355                         ARM_LDR_IMM (code, ARMREG_R0, ARMREG_PC, 0);
6356                         patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
6357                         patch_info->data.name = "mono_arch_throw_corlib_exception";
6358                         patch_info->ip.i = code - cfg->native_code;
6359                         ARM_BL (code, 0);
6360                         *(guint32*)(gpointer)code = exc_class->type_token;
6361                         code += 4;
6362 #endif
6363                         break;
6364                 }
6365                 default:
6366                         /* do nothing */
6367                         break;
6368                 }
6369         }
6370
6371         cfg->code_len = code - cfg->native_code;
6372
6373         g_assert (cfg->code_len < cfg->code_size);
6374
6375 }
6376
6377 #endif /* #ifndef DISABLE_JIT */
6378
6379 void
6380 mono_arch_finish_init (void)
6381 {
6382 }
6383
6384 void
6385 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
6386 {
6387 }
6388
6389 MonoInst*
6390 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
6391 {
6392         /* FIXME: */
6393         return NULL;
6394 }
6395
6396 gboolean
6397 mono_arch_print_tree (MonoInst *tree, int arity)
6398 {
6399         return 0;
6400 }
6401
6402 #ifndef DISABLE_JIT
6403
6404 #endif
6405
6406 guint32
6407 mono_arch_get_patch_offset (guint8 *code)
6408 {
6409         /* OP_AOTCONST */
6410         return 8;
6411 }
6412
6413 void
6414 mono_arch_flush_register_windows (void)
6415 {
6416 }
6417
6418 #ifndef DISABLE_JIT
6419
6420 void
6421 mono_arch_emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoInst *imt_arg)
6422 {
6423         int method_reg = mono_alloc_ireg (cfg);
6424 #ifdef USE_JUMP_TABLES
6425         int use_jumptables = TRUE;
6426 #else
6427         int use_jumptables = FALSE;
6428 #endif
6429
6430         if (cfg->compile_aot) {
6431                 MonoInst *ins;
6432
6433                 call->dynamic_imt_arg = TRUE;
6434
6435                 if (imt_arg) {
6436                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
6437                 } else {
6438                         MONO_INST_NEW (cfg, ins, OP_AOTCONST);
6439                         ins->dreg = method_reg;
6440                         ins->inst_p0 = call->method;
6441                         ins->inst_c1 = MONO_PATCH_INFO_METHODCONST;
6442                         MONO_ADD_INS (cfg->cbb, ins);
6443                 }
6444                 mono_call_inst_add_outarg_reg (cfg, call, method_reg, ARMREG_V5, FALSE);
6445         } else if (cfg->generic_context || imt_arg || mono_use_llvm || use_jumptables) {
6446                 /* Always pass in a register for simplicity */
6447                 call->dynamic_imt_arg = TRUE;
6448
6449                 cfg->uses_rgctx_reg = TRUE;
6450
6451                 if (imt_arg) {
6452                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
6453                 } else {
6454                         MonoInst *ins;
6455
6456                         MONO_INST_NEW (cfg, ins, OP_PCONST);
6457                         ins->inst_p0 = call->method;
6458                         ins->dreg = method_reg;
6459                         MONO_ADD_INS (cfg->cbb, ins);
6460                 }
6461
6462                 mono_call_inst_add_outarg_reg (cfg, call, method_reg, ARMREG_V5, FALSE);
6463         }
6464 }
6465
6466 #endif /* DISABLE_JIT */
6467
6468 MonoMethod*
6469 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
6470 {
6471 #ifdef USE_JUMP_TABLES
6472         return (MonoMethod*)regs [ARMREG_V5];
6473 #else
6474         gpointer method;
6475         guint32 *code_ptr = (guint32*)code;
6476         code_ptr -= 2;
6477         method = GUINT_TO_POINTER (code_ptr [1]);
6478
6479         if (mono_use_llvm)
6480                 /* Passed in V5 */
6481                 return (MonoMethod*)regs [ARMREG_V5];
6482
6483         /* The IMT value is stored in the code stream right after the LDC instruction. */
6484         /* This is no longer true for the gsharedvt_in trampoline */
6485         /*
6486         if (!IS_LDR_PC (code_ptr [0])) {
6487                 g_warning ("invalid code stream, instruction before IMT value is not a LDC in %s() (code %p value 0: 0x%x -1: 0x%x -2: 0x%x)", __FUNCTION__, code, code_ptr [2], code_ptr [1], code_ptr [0]);
6488                 g_assert (IS_LDR_PC (code_ptr [0]));
6489         }
6490         */
6491         if (method == 0)
6492                 /* This is AOTed code, or the gsharedvt trampoline, the IMT method is in V5 */
6493                 return (MonoMethod*)regs [ARMREG_V5];
6494         else
6495                 return (MonoMethod*) method;
6496 #endif
6497 }
6498
6499 MonoVTable*
6500 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
6501 {
6502         return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
6503 }
6504
6505 /* #define ENABLE_WRONG_METHOD_CHECK 1 */
6506 #define BASE_SIZE (6 * 4)
6507 #define BSEARCH_ENTRY_SIZE (4 * 4)
6508 #define CMP_SIZE (3 * 4)
6509 #define BRANCH_SIZE (1 * 4)
6510 #define CALL_SIZE (2 * 4)
6511 #define WMC_SIZE (8 * 4)
6512 #define DISTANCE(A, B) (((gint32)(B)) - ((gint32)(A)))
6513
6514 #ifdef USE_JUMP_TABLES
6515 static void
6516 set_jumptable_element (gpointer *base, guint32 index, gpointer value)
6517 {
6518         g_assert (base [index] == NULL);
6519         base [index] = value;
6520 }
6521 static arminstr_t *
6522 load_element_with_regbase_cond (arminstr_t *code, ARMReg dreg, ARMReg base, guint32 jti, int cond)
6523 {
6524         if (arm_is_imm12 (jti * 4)) {
6525                 ARM_LDR_IMM_COND (code, dreg, base, jti * 4, cond);
6526         } else {
6527                 ARM_MOVW_REG_IMM_COND (code, dreg, (jti * 4) & 0xffff, cond);
6528                 if ((jti * 4) >> 16)
6529                         ARM_MOVT_REG_IMM_COND (code, dreg, ((jti * 4) >> 16) & 0xffff, cond);
6530                 ARM_LDR_REG_REG_SHIFT_COND (code, dreg, base, dreg, ARMSHIFT_LSL, 0, cond);
6531         }
6532         return code;
6533 }
6534 #else
6535 static arminstr_t *
6536 arm_emit_value_and_patch_ldr (arminstr_t *code, arminstr_t *target, guint32 value)
6537 {
6538         guint32 delta = DISTANCE (target, code);
6539         delta -= 8;
6540         g_assert (delta >= 0 && delta <= 0xFFF);
6541         *target = *target | delta;
6542         *code = value;
6543         return code + 1;
6544 }
6545 #endif
6546
6547 #ifdef ENABLE_WRONG_METHOD_CHECK
6548 static void
6549 mini_dump_bad_imt (int input_imt, int compared_imt, int pc)
6550 {
6551         g_print ("BAD IMT comparing %x with expected %x at ip %x", input_imt, compared_imt, pc);
6552         g_assert (0);
6553 }
6554 #endif
6555
6556 gpointer
6557 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
6558         gpointer fail_tramp)
6559 {
6560         int size, i;
6561         arminstr_t *code, *start;
6562 #ifdef USE_JUMP_TABLES
6563         gpointer *jte;
6564 #else
6565         gboolean large_offsets = FALSE;
6566         guint32 **constant_pool_starts;
6567         arminstr_t *vtable_target = NULL;
6568         int extra_space = 0;
6569 #endif
6570 #ifdef ENABLE_WRONG_METHOD_CHECK
6571         char * cond;
6572 #endif
6573
6574         size = BASE_SIZE;
6575 #ifdef USE_JUMP_TABLES
6576         for (i = 0; i < count; ++i) {
6577                 MonoIMTCheckItem *item = imt_entries [i];
6578                 item->chunk_size += 4 * 16;
6579                 if (!item->is_equals)
6580                         imt_entries [item->check_target_idx]->compare_done = TRUE;
6581                 size += item->chunk_size;
6582         }
6583 #else
6584         constant_pool_starts = g_new0 (guint32*, count);
6585
6586         for (i = 0; i < count; ++i) {
6587                 MonoIMTCheckItem *item = imt_entries [i];
6588                 if (item->is_equals) {
6589                         gboolean fail_case = !item->check_target_idx && fail_tramp;
6590
6591                         if (item->has_target_code || !arm_is_imm12 (DISTANCE (vtable, &vtable->vtable[item->value.vtable_slot]))) {
6592                                 item->chunk_size += 32;
6593                                 large_offsets = TRUE;
6594                         }
6595
6596                         if (item->check_target_idx || fail_case) {
6597                                 if (!item->compare_done || fail_case)
6598                                         item->chunk_size += CMP_SIZE;
6599                                 item->chunk_size += BRANCH_SIZE;
6600                         } else {
6601 #ifdef ENABLE_WRONG_METHOD_CHECK
6602                                 item->chunk_size += WMC_SIZE;
6603 #endif
6604                         }
6605                         if (fail_case) {
6606                                 item->chunk_size += 16;
6607                                 large_offsets = TRUE;
6608                         }
6609                         item->chunk_size += CALL_SIZE;
6610                 } else {
6611                         item->chunk_size += BSEARCH_ENTRY_SIZE;
6612                         imt_entries [item->check_target_idx]->compare_done = TRUE;
6613                 }
6614                 size += item->chunk_size;
6615         }
6616
6617         if (large_offsets)
6618                 size += 4 * count; /* The ARM_ADD_REG_IMM to pop the stack */
6619 #endif
6620
6621         if (fail_tramp)
6622                 code = mono_method_alloc_generic_virtual_thunk (domain, size);
6623         else
6624                 code = mono_domain_code_reserve (domain, size);
6625         start = code;
6626
6627 #ifdef DEBUG_IMT
6628         g_print ("Building IMT thunk for class %s %s entries %d code size %d code at %p end %p vtable %p fail_tramp %p\n", vtable->klass->name_space, vtable->klass->name, count, size, start, ((guint8*)start) + size, vtable, fail_tramp);
6629         for (i = 0; i < count; ++i) {
6630                 MonoIMTCheckItem *item = imt_entries [i];
6631                 g_print ("method %d (%p) %s vtable slot %p is_equals %d chunk size %d\n", i, item->key, ((MonoMethod*)item->key)->name, &vtable->vtable [item->value.vtable_slot], item->is_equals, item->chunk_size);
6632         }
6633 #endif
6634
6635 #ifdef USE_JUMP_TABLES
6636         ARM_PUSH3 (code, ARMREG_R0, ARMREG_R1, ARMREG_R2);
6637         /* If jumptables we always pass the IMT method in R5 */
6638         ARM_MOV_REG_REG (code, ARMREG_R0, ARMREG_V5);
6639 #define VTABLE_JTI 0
6640 #define IMT_METHOD_OFFSET 0
6641 #define TARGET_CODE_OFFSET 1
6642 #define JUMP_CODE_OFFSET 2
6643 #define RECORDS_PER_ENTRY 3
6644 #define IMT_METHOD_JTI(idx) (1 + idx * RECORDS_PER_ENTRY + IMT_METHOD_OFFSET)
6645 #define TARGET_CODE_JTI(idx) (1 + idx * RECORDS_PER_ENTRY + TARGET_CODE_OFFSET)
6646 #define JUMP_CODE_JTI(idx) (1 + idx * RECORDS_PER_ENTRY + JUMP_CODE_OFFSET)
6647
6648         jte = mono_jumptable_add_entries (RECORDS_PER_ENTRY * count + 1 /* vtable */);
6649         code = (arminstr_t *) mono_arm_load_jumptable_entry_addr ((guint8 *) code, jte, ARMREG_R2);
6650         ARM_LDR_IMM (code, ARMREG_IP, ARMREG_R2, VTABLE_JTI);
6651         set_jumptable_element (jte, VTABLE_JTI, vtable);
6652 #else
6653         if (large_offsets)
6654                 ARM_PUSH4 (code, ARMREG_R0, ARMREG_R1, ARMREG_IP, ARMREG_PC);
6655         else
6656                 ARM_PUSH2 (code, ARMREG_R0, ARMREG_R1);
6657         ARM_LDR_IMM (code, ARMREG_R0, ARMREG_LR, -4);
6658         vtable_target = code;
6659         ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0);
6660
6661         if (mono_use_llvm) {
6662                 /* LLVM always passes the IMT method in R5 */
6663                 ARM_MOV_REG_REG (code, ARMREG_R0, ARMREG_V5);
6664         } else {
6665                 /* R0 == 0 means we are called from AOT code. In this case, V5 contains the IMT method */
6666                 ARM_CMP_REG_IMM8 (code, ARMREG_R0, 0);
6667                 ARM_MOV_REG_REG_COND (code, ARMREG_R0, ARMREG_V5, ARMCOND_EQ);
6668         }
6669 #endif
6670
6671         for (i = 0; i < count; ++i) {
6672                 MonoIMTCheckItem *item = imt_entries [i];
6673 #ifdef USE_JUMP_TABLES
6674                 guint32 imt_method_jti = 0, target_code_jti = 0;
6675 #else
6676                 arminstr_t *imt_method = NULL, *vtable_offset_ins = NULL, *target_code_ins = NULL;
6677 #endif
6678                 gint32 vtable_offset;
6679
6680                 item->code_target = (guint8*)code;
6681
6682                 if (item->is_equals) {
6683                         gboolean fail_case = !item->check_target_idx && fail_tramp;
6684
6685                         if (item->check_target_idx || fail_case) {
6686                                 if (!item->compare_done || fail_case) {
6687 #ifdef USE_JUMP_TABLES
6688                                         imt_method_jti = IMT_METHOD_JTI (i);
6689                                         code = load_element_with_regbase_cond (code, ARMREG_R1, ARMREG_R2, imt_method_jti, ARMCOND_AL);
6690 #else
6691                                         imt_method = code;
6692                                         ARM_LDR_IMM (code, ARMREG_R1, ARMREG_PC, 0);
6693 #endif
6694                                         ARM_CMP_REG_REG (code, ARMREG_R0, ARMREG_R1);
6695                                 }
6696 #ifdef USE_JUMP_TABLES
6697                                 code = load_element_with_regbase_cond (code, ARMREG_R1, ARMREG_R2, JUMP_CODE_JTI (i), ARMCOND_NE);
6698                                 ARM_BX_COND (code, ARMCOND_NE, ARMREG_R1);
6699                                 item->jmp_code = GUINT_TO_POINTER (JUMP_CODE_JTI (i));
6700 #else
6701                                 item->jmp_code = (guint8*)code;
6702                                 ARM_B_COND (code, ARMCOND_NE, 0);
6703 #endif
6704                         } else {
6705                                 /*Enable the commented code to assert on wrong method*/
6706 #ifdef ENABLE_WRONG_METHOD_CHECK
6707 #ifdef USE_JUMP_TABLES
6708                                 imt_method_jti = IMT_METHOD_JTI (i);
6709                                 code = load_element_with_regbase_cond (code, ARMREG_R1, ARMREG_R2, imt_method_jti, ARMCOND_AL);
6710 #else
6711                                 imt_method = code;
6712                                 ARM_LDR_IMM (code, ARMREG_R1, ARMREG_PC, 0);
6713 #endif
6714                                 ARM_CMP_REG_REG (code, ARMREG_R0, ARMREG_R1);
6715                                 cond = code;
6716                                 ARM_B_COND (code, ARMCOND_EQ, 0);
6717
6718 /* Define this if your system is so bad that gdb is failing. */
6719 #ifdef BROKEN_DEV_ENV
6720                                 ARM_MOV_REG_REG (code, ARMREG_R2, ARMREG_PC);
6721                                 ARM_BL (code, 0);
6722                                 arm_patch (code - 1, mini_dump_bad_imt);
6723 #else
6724                                 ARM_DBRK (code);
6725 #endif
6726                                 arm_patch (cond, code);
6727 #endif
6728                         }
6729
6730                         if (item->has_target_code) {
6731                                 /* Load target address */
6732 #ifdef USE_JUMP_TABLES
6733                                 target_code_jti = TARGET_CODE_JTI (i);
6734                                 code = load_element_with_regbase_cond (code, ARMREG_R1, ARMREG_R2, target_code_jti, ARMCOND_AL);
6735                                 /* Restore registers */
6736                                 ARM_POP3 (code, ARMREG_R0, ARMREG_R1, ARMREG_R2);
6737                                 /*  And branch */
6738                                 ARM_BX (code, ARMREG_R1);
6739                                 set_jumptable_element (jte, target_code_jti, item->value.target_code);
6740 #else
6741                                 target_code_ins = code;
6742                                 ARM_LDR_IMM (code, ARMREG_R1, ARMREG_PC, 0);
6743                                 /* Save it to the fourth slot */
6744                                 ARM_STR_IMM (code, ARMREG_R1, ARMREG_SP, 3 * sizeof (gpointer));
6745                                 /* Restore registers and branch */
6746                                 ARM_POP4 (code, ARMREG_R0, ARMREG_R1, ARMREG_IP, ARMREG_PC);
6747                                 
6748                                 code = arm_emit_value_and_patch_ldr (code, target_code_ins, (gsize)item->value.target_code);
6749 #endif
6750                         } else {
6751                                 vtable_offset = DISTANCE (vtable, &vtable->vtable[item->value.vtable_slot]);
6752                                 if (!arm_is_imm12 (vtable_offset)) {
6753                                         /* 
6754                                          * We need to branch to a computed address but we don't have
6755                                          * a free register to store it, since IP must contain the 
6756                                          * vtable address. So we push the two values to the stack, and
6757                                          * load them both using LDM.
6758                                          */
6759                                         /* Compute target address */
6760 #ifdef USE_JUMP_TABLES
6761                                         ARM_MOVW_REG_IMM (code, ARMREG_R1, vtable_offset & 0xffff);
6762                                         if (vtable_offset >> 16)
6763                                                 ARM_MOVT_REG_IMM (code, ARMREG_R1, (vtable_offset >> 16) & 0xffff);
6764                                         /* IP had vtable base. */
6765                                         ARM_LDR_REG_REG (code, ARMREG_IP, ARMREG_IP, ARMREG_R1);
6766                                         /* Restore registers and branch */
6767                                         ARM_POP3 (code, ARMREG_R0, ARMREG_R1, ARMREG_R2);
6768                                         ARM_BX (code, ARMREG_IP);
6769 #else
6770                                         vtable_offset_ins = code;
6771                                         ARM_LDR_IMM (code, ARMREG_R1, ARMREG_PC, 0);
6772                                         ARM_LDR_REG_REG (code, ARMREG_R1, ARMREG_IP, ARMREG_R1);
6773                                         /* Save it to the fourth slot */
6774                                         ARM_STR_IMM (code, ARMREG_R1, ARMREG_SP, 3 * sizeof (gpointer));
6775                                         /* Restore registers and branch */
6776                                         ARM_POP4 (code, ARMREG_R0, ARMREG_R1, ARMREG_IP, ARMREG_PC);
6777                                 
6778                                         code = arm_emit_value_and_patch_ldr (code, vtable_offset_ins, vtable_offset);
6779 #endif
6780                                 } else {
6781 #ifdef USE_JUMP_TABLES
6782                                         ARM_LDR_IMM (code, ARMREG_IP, ARMREG_IP, vtable_offset);
6783                                         ARM_POP3 (code, ARMREG_R0, ARMREG_R1, ARMREG_R2);
6784                                         ARM_BX (code, ARMREG_IP);
6785 #else
6786                                         ARM_POP2 (code, ARMREG_R0, ARMREG_R1);
6787                                         if (large_offsets)
6788                                                 ARM_ADD_REG_IMM8 (code, ARMREG_SP, ARMREG_SP, 2 * sizeof (gpointer));
6789                                         ARM_LDR_IMM (code, ARMREG_PC, ARMREG_IP, vtable_offset);
6790 #endif
6791                                 }
6792                         }
6793
6794                         if (fail_case) {
6795 #ifdef USE_JUMP_TABLES
6796                                 set_jumptable_element (jte, GPOINTER_TO_UINT (item->jmp_code), code);
6797                                 target_code_jti = TARGET_CODE_JTI (i);
6798                                 /* Load target address */
6799                                 code = load_element_with_regbase_cond (code, ARMREG_R1, ARMREG_R2, target_code_jti, ARMCOND_AL);
6800                                 /* Restore registers */
6801                                 ARM_POP3 (code, ARMREG_R0, ARMREG_R1, ARMREG_R2);
6802                                 /* And branch */
6803                                 ARM_BX (code, ARMREG_R1);
6804                                 set_jumptable_element (jte, target_code_jti, fail_tramp);
6805 #else
6806                                 arm_patch (item->jmp_code, (guchar*)code);
6807
6808                                 target_code_ins = code;
6809                                 /* Load target address */
6810                                 ARM_LDR_IMM (code, ARMREG_R1, ARMREG_PC, 0);
6811                                 /* Save it to the fourth slot */
6812                                 ARM_STR_IMM (code, ARMREG_R1, ARMREG_SP, 3 * sizeof (gpointer));
6813                                 /* Restore registers and branch */
6814                                 ARM_POP4 (code, ARMREG_R0, ARMREG_R1, ARMREG_IP, ARMREG_PC);
6815                                 
6816                                 code = arm_emit_value_and_patch_ldr (code, target_code_ins, (gsize)fail_tramp);
6817 #endif
6818                                 item->jmp_code = NULL;
6819                         }
6820
6821 #ifdef USE_JUMP_TABLES
6822                         if (imt_method_jti)
6823                                 set_jumptable_element (jte, imt_method_jti, item->key);
6824 #else
6825                         if (imt_method)
6826                                 code = arm_emit_value_and_patch_ldr (code, imt_method, (guint32)item->key);
6827
6828                         /*must emit after unconditional branch*/
6829                         if (vtable_target) {
6830                                 code = arm_emit_value_and_patch_ldr (code, vtable_target, (guint32)vtable);
6831                                 item->chunk_size += 4;
6832                                 vtable_target = NULL;
6833                         }
6834
6835                         /*We reserve the space for bsearch IMT values after the first entry with an absolute jump*/
6836                         constant_pool_starts [i] = code;
6837                         if (extra_space) {
6838                                 code += extra_space;
6839                                 extra_space = 0;
6840                         }
6841 #endif
6842                 } else {
6843 #ifdef USE_JUMP_TABLES
6844                         code = load_element_with_regbase_cond (code, ARMREG_R1, ARMREG_R2, IMT_METHOD_JTI (i), ARMCOND_AL);
6845                         ARM_CMP_REG_REG (code, ARMREG_R0, ARMREG_R1);
6846                         code = load_element_with_regbase_cond (code, ARMREG_R1, ARMREG_R2, JUMP_CODE_JTI (i), ARMCOND_HS);
6847                         ARM_BX_COND (code, ARMCOND_HS, ARMREG_R1);
6848                         item->jmp_code = GUINT_TO_POINTER (JUMP_CODE_JTI (i));
6849 #else
6850                         ARM_LDR_IMM (code, ARMREG_R1, ARMREG_PC, 0);
6851                         ARM_CMP_REG_REG (code, ARMREG_R0, ARMREG_R1);
6852
6853                         item->jmp_code = (guint8*)code;
6854                         ARM_B_COND (code, ARMCOND_HS, 0);
6855                         ++extra_space;
6856 #endif
6857                 }
6858         }
6859
6860         for (i = 0; i < count; ++i) {
6861                 MonoIMTCheckItem *item = imt_entries [i];
6862                 if (item->jmp_code) {
6863                         if (item->check_target_idx)
6864 #ifdef USE_JUMP_TABLES
6865                                 set_jumptable_element (jte, GPOINTER_TO_UINT (item->jmp_code), imt_entries [item->check_target_idx]->code_target);
6866 #else
6867                                 arm_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
6868 #endif
6869                 }
6870                 if (i > 0 && item->is_equals) {
6871                         int j;
6872 #ifdef USE_JUMP_TABLES
6873                         for (j = i - 1; j >= 0 && !imt_entries [j]->is_equals; --j)
6874                                 set_jumptable_element (jte, IMT_METHOD_JTI (j), imt_entries [j]->key);
6875 #else
6876                         arminstr_t *space_start = constant_pool_starts [i];
6877                         for (j = i - 1; j >= 0 && !imt_entries [j]->is_equals; --j) {
6878                                 space_start = arm_emit_value_and_patch_ldr (space_start, (arminstr_t*)imt_entries [j]->code_target, (guint32)imt_entries [j]->key);
6879                         }
6880 #endif
6881                 }
6882         }
6883
6884 #ifdef DEBUG_IMT
6885         {
6886                 char *buff = g_strdup_printf ("thunk_for_class_%s_%s_entries_%d", vtable->klass->name_space, vtable->klass->name, count);
6887                 mono_disassemble_code (NULL, (guint8*)start, size, buff);
6888                 g_free (buff);
6889         }
6890 #endif
6891
6892 #ifndef USE_JUMP_TABLES
6893         g_free (constant_pool_starts);
6894 #endif
6895
6896         mono_arch_flush_icache ((guint8*)start, size);
6897         mono_stats.imt_thunks_size += code - start;
6898
6899         g_assert (DISTANCE (start, code) <= size);
6900         return start;
6901 }
6902
6903 mgreg_t
6904 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
6905 {
6906         return ctx->regs [reg];
6907 }
6908
6909 void
6910 mono_arch_context_set_int_reg (MonoContext *ctx, int reg, mgreg_t val)
6911 {
6912         ctx->regs [reg] = val;
6913 }
6914
6915 /*
6916  * mono_arch_get_trampolines:
6917  *
6918  *   Return a list of MonoTrampInfo structures describing arch specific trampolines
6919  * for AOT.
6920  */
6921 GSList *
6922 mono_arch_get_trampolines (gboolean aot)
6923 {
6924         return mono_arm_get_exception_trampolines (aot);
6925 }
6926
6927 #if defined(MONO_ARCH_SOFT_DEBUG_SUPPORTED)
6928 /*
6929  * mono_arch_set_breakpoint:
6930  *
6931  *   Set a breakpoint at the native code corresponding to JI at NATIVE_OFFSET.
6932  * The location should contain code emitted by OP_SEQ_POINT.
6933  */
6934 void
6935 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
6936 {
6937         guint8 *code = ip;
6938         guint32 native_offset = ip - (guint8*)ji->code_start;
6939         MonoDebugOptions *opt = mini_get_debug_options ();
6940
6941         if (opt->soft_breakpoints) {
6942                 g_assert (!ji->from_aot);
6943                 code += 4;
6944                 ARM_BLX_REG (code, ARMREG_LR);
6945                 mono_arch_flush_icache (code - 4, 4);
6946         } else if (ji->from_aot) {
6947                 SeqPointInfo *info = mono_arch_get_seq_point_info (mono_domain_get (), ji->code_start);
6948
6949                 g_assert (native_offset % 4 == 0);
6950                 g_assert (info->bp_addrs [native_offset / 4] == 0);
6951                 info->bp_addrs [native_offset / 4] = bp_trigger_page;
6952         } else {
6953                 int dreg = ARMREG_LR;
6954
6955                 /* Read from another trigger page */
6956 #ifdef USE_JUMP_TABLES
6957                 gpointer *jte = mono_jumptable_add_entry ();
6958                 code = mono_arm_load_jumptable_entry (code, jte, dreg);
6959                 jte [0] = bp_trigger_page;
6960 #else
6961                 ARM_LDR_IMM (code, dreg, ARMREG_PC, 0);
6962                 ARM_B (code, 0);
6963                 *(int*)code = (int)bp_trigger_page;
6964                 code += 4;
6965 #endif
6966                 ARM_LDR_IMM (code, dreg, dreg, 0);
6967
6968                 mono_arch_flush_icache (code - 16, 16);
6969
6970 #if 0
6971                 /* This is currently implemented by emitting an SWI instruction, which 
6972                  * qemu/linux seems to convert to a SIGILL.
6973                  */
6974                 *(int*)code = (0xef << 24) | 8;
6975                 code += 4;
6976                 mono_arch_flush_icache (code - 4, 4);
6977 #endif
6978         }
6979 }
6980
6981 /*
6982  * mono_arch_clear_breakpoint:
6983  *
6984  *   Clear the breakpoint at IP.
6985  */
6986 void
6987 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
6988 {
6989         MonoDebugOptions *opt = mini_get_debug_options ();
6990         guint8 *code = ip;
6991         int i;
6992
6993         if (opt->soft_breakpoints) {
6994                 g_assert (!ji->from_aot);
6995                 code += 4;
6996                 ARM_NOP (code);
6997                 mono_arch_flush_icache (code - 4, 4);
6998         } else if (ji->from_aot) {
6999                 guint32 native_offset = ip - (guint8*)ji->code_start;
7000                 SeqPointInfo *info = mono_arch_get_seq_point_info (mono_domain_get (), ji->code_start);
7001
7002                 g_assert (native_offset % 4 == 0);
7003                 g_assert (info->bp_addrs [native_offset / 4] == bp_trigger_page);
7004                 info->bp_addrs [native_offset / 4] = 0;
7005         } else {
7006                 for (i = 0; i < 4; ++i)
7007                         ARM_NOP (code);
7008
7009                 mono_arch_flush_icache (ip, code - ip);
7010         }
7011 }
7012         
7013 /*
7014  * mono_arch_start_single_stepping:
7015  *
7016  *   Start single stepping.
7017  */
7018 void
7019 mono_arch_start_single_stepping (void)
7020 {
7021         if (ss_trigger_page)
7022                 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
7023         else
7024                 ss_trigger_var = 1;
7025 }
7026         
7027 /*
7028  * mono_arch_stop_single_stepping:
7029  *
7030  *   Stop single stepping.
7031  */
7032 void
7033 mono_arch_stop_single_stepping (void)
7034 {
7035         if (ss_trigger_page)
7036                 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
7037         else
7038                 ss_trigger_var = 0;
7039 }
7040
7041 #if __APPLE__
7042 #define DBG_SIGNAL SIGBUS
7043 #else
7044 #define DBG_SIGNAL SIGSEGV
7045 #endif
7046
7047 /*
7048  * mono_arch_is_single_step_event:
7049  *
7050  *   Return whenever the machine state in SIGCTX corresponds to a single
7051  * step event.
7052  */
7053 gboolean
7054 mono_arch_is_single_step_event (void *info, void *sigctx)
7055 {
7056         siginfo_t *sinfo = info;
7057
7058         if (!ss_trigger_page)
7059                 return FALSE;
7060
7061         /* Sometimes the address is off by 4 */
7062         if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
7063                 return TRUE;
7064         else
7065                 return FALSE;
7066 }
7067
7068 /*
7069  * mono_arch_is_breakpoint_event:
7070  *
7071  *   Return whenever the machine state in SIGCTX corresponds to a breakpoint event.
7072  */
7073 gboolean
7074 mono_arch_is_breakpoint_event (void *info, void *sigctx)
7075 {
7076         siginfo_t *sinfo = info;
7077
7078         if (!ss_trigger_page)
7079                 return FALSE;
7080
7081         if (sinfo->si_signo == DBG_SIGNAL) {
7082                 /* Sometimes the address is off by 4 */
7083                 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
7084                         return TRUE;
7085                 else
7086                         return FALSE;
7087         } else {
7088                 return FALSE;
7089         }
7090 }
7091
7092 /*
7093  * mono_arch_skip_breakpoint:
7094  *
7095  *   See mini-amd64.c for docs.
7096  */
7097 void
7098 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
7099 {
7100         MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
7101 }
7102
7103 /*
7104  * mono_arch_skip_single_step:
7105  *
7106  *   See mini-amd64.c for docs.
7107  */
7108 void
7109 mono_arch_skip_single_step (MonoContext *ctx)
7110 {
7111         MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
7112 }
7113
7114 #endif /* MONO_ARCH_SOFT_DEBUG_SUPPORTED */
7115
7116 /*
7117  * mono_arch_get_seq_point_info:
7118  *
7119  *   See mini-amd64.c for docs.
7120  */
7121 gpointer
7122 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
7123 {
7124         SeqPointInfo *info;
7125         MonoJitInfo *ji;
7126
7127         // FIXME: Add a free function
7128
7129         mono_domain_lock (domain);
7130         info = g_hash_table_lookup (domain_jit_info (domain)->arch_seq_points, 
7131                                                                 code);
7132         mono_domain_unlock (domain);
7133
7134         if (!info) {
7135                 ji = mono_jit_info_table_find (domain, (char*)code);
7136                 g_assert (ji);
7137
7138                 info = g_malloc0 (sizeof (SeqPointInfo) + ji->code_size);
7139
7140                 info->ss_trigger_page = ss_trigger_page;
7141                 info->bp_trigger_page = bp_trigger_page;
7142
7143                 mono_domain_lock (domain);
7144                 g_hash_table_insert (domain_jit_info (domain)->arch_seq_points,
7145                                                          code, info);
7146                 mono_domain_unlock (domain);
7147         }
7148
7149         return info;
7150 }
7151
7152 void
7153 mono_arch_init_lmf_ext (MonoLMFExt *ext, gpointer prev_lmf)
7154 {
7155         ext->lmf.previous_lmf = prev_lmf;
7156         /* Mark that this is a MonoLMFExt */
7157         ext->lmf.previous_lmf = (gpointer)(((gssize)ext->lmf.previous_lmf) | 2);
7158         ext->lmf.sp = (gssize)ext;
7159 }
7160
7161 /*
7162  * mono_arch_set_target:
7163  *
7164  *   Set the target architecture the JIT backend should generate code for, in the form
7165  * of a GNU target triplet. Only used in AOT mode.
7166  */
7167 void
7168 mono_arch_set_target (char *mtriple)
7169 {
7170         /* The GNU target triple format is not very well documented */
7171         if (strstr (mtriple, "armv7")) {
7172                 v5_supported = TRUE;
7173                 v6_supported = TRUE;
7174                 v7_supported = TRUE;
7175         }
7176         if (strstr (mtriple, "armv6")) {
7177                 v5_supported = TRUE;
7178                 v6_supported = TRUE;
7179         }
7180         if (strstr (mtriple, "armv7s")) {
7181                 v7s_supported = TRUE;
7182         }
7183         if (strstr (mtriple, "thumbv7s")) {
7184                 v5_supported = TRUE;
7185                 v6_supported = TRUE;
7186                 v7_supported = TRUE;
7187                 v7s_supported = TRUE;
7188                 thumb_supported = TRUE;
7189                 thumb2_supported = TRUE;
7190         }
7191         if (strstr (mtriple, "darwin") || strstr (mtriple, "ios")) {
7192                 v5_supported = TRUE;
7193                 v6_supported = TRUE;
7194                 thumb_supported = TRUE;
7195                 iphone_abi = TRUE;
7196         }
7197         if (strstr (mtriple, "gnueabi"))
7198                 eabi_supported = TRUE;
7199 }
7200
7201 gboolean
7202 mono_arch_opcode_supported (int opcode)
7203 {
7204         switch (opcode) {
7205         case OP_ATOMIC_ADD_I4:
7206         case OP_ATOMIC_EXCHANGE_I4:
7207         case OP_ATOMIC_CAS_I4:
7208                 return v7_supported;
7209         default:
7210                 return FALSE;
7211         }
7212 }
7213
7214 #if defined(ENABLE_GSHAREDVT)
7215
7216 #include "../../../mono-extensions/mono/mini/mini-arm-gsharedvt.c"
7217
7218 #endif /* !MONOTOUCH */