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