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