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