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