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