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