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