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