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