2 * tramp-arm.c: JIT trampoline code for ARM
5 * Paolo Molaro (lupus@ximian.com)
7 * (C) 2001 Ximian, Inc.
13 #include <mono/metadata/appdomain.h>
14 #include <mono/metadata/marshal.h>
15 #include <mono/metadata/tabledefs.h>
16 #include <mono/arch/arm/arm-codegen.h>
21 static guint8
* nullified_class_init_trampoline
;
24 mono_arch_patch_callsite (guint8
*method_start
, guint8
*code_ptr
, guint8
*addr
)
26 guint32
*code
= (guint32
*)code_ptr
;
28 /* This is the 'bl' or the 'mov pc' instruction */
32 * Note that methods are called also with the bl opcode.
34 if ((((*code
) >> 25) & 7) == 5) {
35 /*g_print ("direct patching\n");*/
36 arm_patch ((guint8
*)code
, addr
);
37 mono_arch_flush_icache ((guint8
*)code
, 4);
41 if ((((*code
) >> 20) & 0xFF) == 0x12) {
42 /*g_print ("patching bx\n");*/
43 arm_patch ((guint8
*)code
, addr
);
44 mono_arch_flush_icache ((guint8
*)(code
- 2), 4);
48 g_assert_not_reached ();
52 mono_arch_patch_plt_entry (guint8
*code
, gpointer
*got
, mgreg_t
*regs
, guint8
*addr
)
56 /* Patch the jump table entry used by the plt entry */
57 if (*(guint32
*)code
== 0xe59fc000) {
58 /* ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0); */
59 guint32 offset
= ((guint32
*)code
)[2];
61 jump_entry
= code
+ offset
+ 12;
63 g_assert_not_reached ();
66 *(guint8
**)jump_entry
= addr
;
70 mono_arch_nullify_class_init_trampoline (guint8
*code
, mgreg_t
*regs
)
72 mono_arch_patch_callsite (NULL
, code
, nullified_class_init_trampoline
);
76 mono_arch_nullify_plt_entry (guint8
*code
, mgreg_t
*regs
)
78 if (mono_aot_only
&& !nullified_class_init_trampoline
)
79 nullified_class_init_trampoline
= mono_aot_get_trampoline ("nullified_class_init_trampoline");
81 mono_arch_patch_plt_entry (code
, NULL
, regs
, nullified_class_init_trampoline
);
86 #define arm_is_imm12(v) ((int)(v) > -4096 && (int)(v) < 4096)
89 * Return the instruction to jump from code to target, 0 if not
90 * reachable with a single instruction
93 branch_for_target_reachable (guint8
*branch
, guint8
*target
)
95 gint diff
= target
- branch
- 8;
96 g_assert ((diff
& 3) == 0);
99 return (ARMCOND_AL
<< ARMCOND_SHIFT
) | (ARM_BR_TAG
) | (diff
>> 2);
101 /* diff between 0 and -33554432 */
102 if (diff
>= -33554432)
103 return (ARMCOND_AL
<< ARMCOND_SHIFT
) | (ARM_BR_TAG
) | ((diff
>> 2) & ~0xff000000);
108 static inline guint8
*
109 emit_bx (guint8
* code
, int reg
)
111 if (mono_arm_thumb_supported ())
114 ARM_MOV_REG_REG (code
, ARMREG_PC
, reg
);
118 /* Stack size for trampoline function
120 #define STACK (sizeof (MonoLMF))
122 /* Method-specific trampoline code fragment size */
123 #define METHOD_TRAMPOLINE_SIZE 64
125 /* Jump-specific trampoline code fragment size */
126 #define JUMP_TRAMPOLINE_SIZE 64
128 #define GEN_TRAMP_SIZE 196
131 mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type
, MonoTrampInfo
**info
, gboolean aot
)
133 guint8
*buf
, *code
= NULL
;
134 guint8
*load_get_lmf_addr
, *load_trampoline
;
137 GSList
*unwind_ops
= NULL
;
138 MonoJumpInfo
*ji
= NULL
;
140 /* Now we'll create in 'buf' the ARM trampoline code. This
141 is the trampoline code common to all methods */
143 code
= buf
= mono_global_codeman_reserve (GEN_TRAMP_SIZE
);
146 * At this point lr points to the specific arg and sp points to the saved
147 * regs on the stack (all but PC and SP). The original LR value has been
148 * saved as sp + LR_OFFSET by the push in the specific trampoline
150 #define LR_OFFSET (sizeof (gpointer) * 13)
152 // FIXME: Finish the unwind info, the current info allows us to unwind
153 // when the trampoline is not in the epilog
155 // CFA = SP + (num registers pushed) * 4
156 cfa_offset
= 14 * sizeof (gpointer
);
157 mono_add_unwind_op_def_cfa (unwind_ops
, code
, buf
, ARMREG_SP
, cfa_offset
);
158 // PC saved at sp+LR_OFFSET
159 mono_add_unwind_op_offset (unwind_ops
, code
, buf
, ARMREG_LR
, -4);
161 ARM_MOV_REG_REG (code
, ARMREG_V1
, ARMREG_SP
);
162 if (aot
&& tramp_type
!= MONO_TRAMPOLINE_GENERIC_CLASS_INIT
) {
164 * The trampoline contains a pc-relative offset to the got slot
165 * preceeding the got slot where the value is stored. The offset can be
168 ARM_LDR_IMM (code
, ARMREG_V2
, ARMREG_LR
, 0);
169 ARM_ADD_REG_IMM (code
, ARMREG_V2
, ARMREG_V2
, 4, 0);
170 ARM_LDR_REG_REG (code
, ARMREG_V2
, ARMREG_V2
, ARMREG_LR
);
172 if (tramp_type
!= MONO_TRAMPOLINE_GENERIC_CLASS_INIT
)
173 ARM_LDR_IMM (code
, ARMREG_V2
, ARMREG_LR
, 0);
175 ARM_MOV_REG_REG (code
, ARMREG_V2
, MONO_ARCH_VTABLE_REG
);
177 ARM_LDR_IMM (code
, ARMREG_V3
, ARMREG_SP
, LR_OFFSET
);
179 /* ok, now we can continue with the MonoLMF setup, mostly untouched
180 * from emit_prolog in mini-arm.c
181 * This is a synthetized call to mono_get_lmf_addr ()
184 ji
= mono_patch_info_list_prepend (ji
, code
- buf
, MONO_PATCH_INFO_JIT_ICALL_ADDR
, "mono_get_lmf_addr");
185 ARM_LDR_IMM (code
, ARMREG_R0
, ARMREG_PC
, 0);
187 *(gpointer
*)code
= NULL
;
189 ARM_LDR_REG_REG (code
, ARMREG_R0
, ARMREG_PC
, ARMREG_R0
);
191 load_get_lmf_addr
= code
;
194 ARM_MOV_REG_REG (code
, ARMREG_LR
, ARMREG_PC
);
195 code
= emit_bx (code
, ARMREG_R0
);
197 /* we build the MonoLMF structure on the stack - see mini-arm.h
198 * The pointer to the struct is put in r1.
199 * the iregs array is already allocated on the stack by push.
201 ARM_SUB_REG_IMM8 (code
, ARMREG_SP
, ARMREG_SP
, sizeof (MonoLMF
) - sizeof (guint
) * 14);
202 cfa_offset
+= sizeof (MonoLMF
) - sizeof (guint
) * 14;
203 mono_add_unwind_op_def_cfa_offset (unwind_ops
, code
, buf
, cfa_offset
);
204 ARM_ADD_REG_IMM8 (code
, ARMREG_R1
, ARMREG_SP
, STACK
- sizeof (MonoLMF
));
205 /* r0 is the result from mono_get_lmf_addr () */
206 ARM_STR_IMM (code
, ARMREG_R0
, ARMREG_R1
, G_STRUCT_OFFSET (MonoLMF
, lmf_addr
));
207 /* new_lmf->previous_lmf = *lmf_addr */
208 ARM_LDR_IMM (code
, ARMREG_R2
, ARMREG_R0
, G_STRUCT_OFFSET (MonoLMF
, previous_lmf
));
209 ARM_STR_IMM (code
, ARMREG_R2
, ARMREG_R1
, G_STRUCT_OFFSET (MonoLMF
, previous_lmf
));
210 /* *(lmf_addr) = r1 */
211 ARM_STR_IMM (code
, ARMREG_R1
, ARMREG_R0
, G_STRUCT_OFFSET (MonoLMF
, previous_lmf
));
212 /* save method info (it's in v2) */
213 if ((tramp_type
== MONO_TRAMPOLINE_JIT
) || (tramp_type
== MONO_TRAMPOLINE_JUMP
))
214 ARM_STR_IMM (code
, ARMREG_V2
, ARMREG_R1
, G_STRUCT_OFFSET (MonoLMF
, method
));
216 ARM_MOV_REG_IMM8 (code
, ARMREG_R2
, 0);
217 ARM_STR_IMM (code
, ARMREG_R2
, ARMREG_R1
, G_STRUCT_OFFSET (MonoLMF
, method
));
219 ARM_STR_IMM (code
, ARMREG_SP
, ARMREG_R1
, G_STRUCT_OFFSET (MonoLMF
, ebp
));
220 /* save the IP (caller ip) */
221 if (tramp_type
== MONO_TRAMPOLINE_JUMP
) {
222 ARM_MOV_REG_IMM8 (code
, ARMREG_R2
, 0);
224 /* assumes STACK == sizeof (MonoLMF) */
225 ARM_LDR_IMM (code
, ARMREG_R2
, ARMREG_SP
, (G_STRUCT_OFFSET (MonoLMF
, iregs
) + 13*4));
227 ARM_STR_IMM (code
, ARMREG_R2
, ARMREG_R1
, G_STRUCT_OFFSET (MonoLMF
, eip
));
230 * Now we're ready to call xxx_trampoline ().
232 /* Arg 1: the saved registers. It was put in v1 */
233 ARM_MOV_REG_REG (code
, ARMREG_R0
, ARMREG_V1
);
235 /* Arg 2: code (next address to the instruction that called us) */
236 if (tramp_type
== MONO_TRAMPOLINE_JUMP
) {
237 ARM_MOV_REG_IMM8 (code
, ARMREG_R1
, 0);
239 ARM_MOV_REG_REG (code
, ARMREG_R1
, ARMREG_V3
);
242 /* Arg 3: the specific argument, stored in v2
244 ARM_MOV_REG_REG (code
, ARMREG_R2
, ARMREG_V2
);
247 char *icall_name
= g_strdup_printf ("trampoline_func_%d", tramp_type
);
248 ji
= mono_patch_info_list_prepend (ji
, code
- buf
, MONO_PATCH_INFO_JIT_ICALL_ADDR
, icall_name
);
249 ARM_LDR_IMM (code
, ARMREG_IP
, ARMREG_PC
, 0);
251 *(gpointer
*)code
= NULL
;
253 ARM_LDR_REG_REG (code
, ARMREG_IP
, ARMREG_PC
, ARMREG_IP
);
255 load_trampoline
= code
;
259 ARM_MOV_REG_REG (code
, ARMREG_LR
, ARMREG_PC
);
260 code
= emit_bx (code
, ARMREG_IP
);
262 /* OK, code address is now on r0. Move it to the place on the stack
263 * where IP was saved (it is now no more useful to us and it can be
264 * clobbered). This way we can just restore all the regs in one inst
267 ARM_STR_IMM (code
, ARMREG_R0
, ARMREG_V1
, (ARMREG_R12
* 4));
269 /* Check for thread interruption */
270 /* This is not perf critical code so no need to check the interrupt flag */
272 * Have to call the _force_ variant, since there could be a protected wrapper on the top of the stack.
275 ji
= mono_patch_info_list_prepend (ji
, code
- buf
, MONO_PATCH_INFO_JIT_ICALL_ADDR
, "mono_thread_force_interruption_checkpoint");
276 ARM_LDR_IMM (code
, ARMREG_IP
, ARMREG_PC
, 0);
278 *(gpointer
*)code
= NULL
;
280 ARM_LDR_REG_REG (code
, ARMREG_IP
, ARMREG_PC
, ARMREG_IP
);
282 ARM_LDR_IMM (code
, ARMREG_IP
, ARMREG_PC
, 0);
284 *(gpointer
*)code
= mono_thread_force_interruption_checkpoint
;
287 ARM_MOV_REG_REG (code
, ARMREG_LR
, ARMREG_PC
);
288 code
= emit_bx (code
, ARMREG_IP
);
291 * Now we restore the MonoLMF (see emit_epilogue in mini-arm.c)
292 * and the rest of the registers, so the method called will see
293 * the same state as before we executed.
294 * The pointer to MonoLMF is in r2.
296 ARM_MOV_REG_REG (code
, ARMREG_R2
, ARMREG_SP
);
297 /* ip = previous_lmf */
298 ARM_LDR_IMM (code
, ARMREG_IP
, ARMREG_R2
, G_STRUCT_OFFSET (MonoLMF
, previous_lmf
));
300 ARM_LDR_IMM (code
, ARMREG_LR
, ARMREG_R2
, G_STRUCT_OFFSET (MonoLMF
, lmf_addr
));
301 /* *(lmf_addr) = previous_lmf */
302 ARM_STR_IMM (code
, ARMREG_IP
, ARMREG_LR
, G_STRUCT_OFFSET (MonoLMF
, previous_lmf
));
304 /* Non-standard function epilogue. Instead of doing a proper
305 * return, we just jump to the compiled code.
307 /* Restore the registers and jump to the code:
308 * Note that IP has been conveniently set to the method addr.
310 ARM_ADD_REG_IMM8 (code
, ARMREG_SP
, ARMREG_SP
, sizeof (MonoLMF
) - sizeof (guint
) * 14);
311 ARM_POP_NWB (code
, 0x5fff);
312 if (tramp_type
== MONO_TRAMPOLINE_RGCTX_LAZY_FETCH
)
313 ARM_MOV_REG_REG (code
, ARMREG_R0
, ARMREG_IP
);
314 /* do we need to set sp? */
315 ARM_ADD_REG_IMM8 (code
, ARMREG_SP
, ARMREG_SP
, (14 * 4));
316 if ((tramp_type
== MONO_TRAMPOLINE_CLASS_INIT
) || (tramp_type
== MONO_TRAMPOLINE_GENERIC_CLASS_INIT
) || (tramp_type
== MONO_TRAMPOLINE_RGCTX_LAZY_FETCH
))
317 code
= emit_bx (code
, ARMREG_LR
);
319 code
= emit_bx (code
, ARMREG_IP
);
321 constants
= (gpointer
*)code
;
322 constants
[0] = mono_get_lmf_addr
;
323 constants
[1] = (gpointer
)mono_get_trampoline_func (tramp_type
);
326 /* backpatch by emitting the missing instructions skipped above */
327 ARM_LDR_IMM (load_get_lmf_addr
, ARMREG_R0
, ARMREG_PC
, (code
- load_get_lmf_addr
- 8));
328 ARM_LDR_IMM (load_trampoline
, ARMREG_IP
, ARMREG_PC
, (code
+ 4 - load_trampoline
- 8));
333 /* Flush instruction cache, since we've generated code */
334 mono_arch_flush_icache (buf
, code
- buf
);
337 g_assert ((code
- buf
) <= GEN_TRAMP_SIZE
);
339 if (tramp_type
== MONO_TRAMPOLINE_CLASS_INIT
)
340 /* Initialize the nullified class init trampoline used in the AOT case */
341 nullified_class_init_trampoline
= mono_arch_get_nullified_class_init_trampoline (NULL
);
344 *info
= mono_tramp_info_create (g_strdup_printf ("generic_trampoline_%d", tramp_type
), buf
, code
- buf
, ji
, unwind_ops
);
350 mono_arch_get_nullified_class_init_trampoline (MonoTrampInfo
**info
)
354 code
= buf
= mono_global_codeman_reserve (16);
356 code
= emit_bx (code
, ARMREG_LR
);
358 mono_arch_flush_icache (buf
, code
- buf
);
361 *info
= mono_tramp_info_create (g_strdup_printf ("nullified_class_init_trampoline"), buf
, code
- buf
, NULL
, NULL
);
366 #define SPEC_TRAMP_SIZE 24
369 mono_arch_create_specific_trampoline (gpointer arg1
, MonoTrampolineType tramp_type
, MonoDomain
*domain
, guint32
*code_len
)
371 guint8
*code
, *buf
, *tramp
;
373 guint32 short_branch
, size
= SPEC_TRAMP_SIZE
;
375 tramp
= mono_get_trampoline_code (tramp_type
);
377 mono_domain_lock (domain
);
378 code
= buf
= mono_domain_code_reserve_align (domain
, size
, 4);
379 if ((short_branch
= branch_for_target_reachable (code
+ 8, tramp
))) {
381 mono_domain_code_commit (domain
, code
, SPEC_TRAMP_SIZE
, size
);
383 mono_domain_unlock (domain
);
385 /* we could reduce this to 12 bytes if tramp is within reach:
389 * The called code can access method using the lr register
390 * A 20 byte sequence could be:
392 * ARM_MOV_REG_REG (lr, pc)
393 * ARM_LDR_IMM (pc, pc, 0)
397 /* We save all the registers, except PC and SP */
398 ARM_PUSH (code
, 0x5fff);
400 constants
= (gpointer
*)code
;
401 constants
[0] = GUINT_TO_POINTER (short_branch
| (1 << 24));
402 constants
[1] = arg1
;
405 ARM_LDR_IMM (code
, ARMREG_R1
, ARMREG_PC
, 8); /* temp reg */
406 ARM_MOV_REG_REG (code
, ARMREG_LR
, ARMREG_PC
);
407 code
= emit_bx (code
, ARMREG_R1
);
409 constants
= (gpointer
*)code
;
410 constants
[0] = arg1
;
411 constants
[1] = tramp
;
415 /* Flush instruction cache, since we've generated code */
416 mono_arch_flush_icache (buf
, code
- buf
);
418 g_assert ((code
- buf
) <= size
);
421 *code_len
= code
- buf
;
427 * mono_arch_get_unbox_trampoline:
428 * @gsctx: the generic sharing context
430 * @addr: pointer to native code for @m
432 * when value type methods are called through the vtable we need to unbox the
433 * this argument. This method returns a pointer to a trampoline which does
434 * unboxing before calling the method
437 mono_arch_get_unbox_trampoline (MonoGenericSharingContext
*gsctx
, MonoMethod
*m
, gpointer addr
)
439 guint8
*code
, *start
;
441 MonoDomain
*domain
= mono_domain_get ();
443 if (MONO_TYPE_ISSTRUCT (mono_method_signature (m
)->ret
))
446 start
= code
= mono_domain_code_reserve (domain
, 16);
448 ARM_LDR_IMM (code
, ARMREG_IP
, ARMREG_PC
, 4);
449 ARM_ADD_REG_IMM8 (code
, this_pos
, this_pos
, sizeof (MonoObject
));
450 code
= emit_bx (code
, ARMREG_IP
);
451 *(guint32
*)code
= (guint32
)addr
;
453 mono_arch_flush_icache (start
, code
- start
);
454 g_assert ((code
- start
) <= 16);
455 /*g_print ("unbox trampoline at %d for %s:%s\n", this_pos, m->klass->name, m->name);
456 g_print ("unbox code is at %p for method at %p\n", start, addr);*/
462 mono_arch_get_static_rgctx_trampoline (MonoMethod
*m
, MonoMethodRuntimeGenericContext
*mrgctx
, gpointer addr
)
464 guint8
*code
, *start
;
467 MonoDomain
*domain
= mono_domain_get ();
471 start
= code
= mono_domain_code_reserve (domain
, buf_len
);
473 ARM_LDR_IMM (code
, MONO_ARCH_RGCTX_REG
, ARMREG_PC
, 0);
474 ARM_LDR_IMM (code
, ARMREG_PC
, ARMREG_PC
, 0);
475 *(guint32
*)code
= (guint32
)mrgctx
;
477 *(guint32
*)code
= (guint32
)addr
;
480 g_assert ((code
- start
) <= buf_len
);
482 mono_arch_flush_icache (start
, code
- start
);
488 mono_arch_create_rgctx_lazy_fetch_trampoline (guint32 slot
, MonoTrampInfo
**info
, gboolean aot
)
494 guint8
**rgctx_null_jumps
;
498 MonoJumpInfo
*ji
= NULL
;
499 GSList
*unwind_ops
= NULL
;
501 mrgctx
= MONO_RGCTX_SLOT_IS_MRGCTX (slot
);
502 index
= MONO_RGCTX_SLOT_INDEX (slot
);
504 index
+= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT
/ sizeof (gpointer
);
505 for (depth
= 0; ; ++depth
) {
506 int size
= mono_class_rgctx_get_array_size (depth
, mrgctx
);
508 if (index
< size
- 1)
513 tramp_size
= 64 + 16 * depth
;
515 code
= buf
= mono_global_codeman_reserve (tramp_size
);
517 rgctx_null_jumps
= g_malloc (sizeof (guint8
*) * (depth
+ 2));
520 /* The vtable/mrgctx is in R0 */
521 g_assert (MONO_ARCH_VTABLE_REG
== ARMREG_R0
);
525 ARM_MOV_REG_REG (code
, ARMREG_R1
, ARMREG_R0
);
527 /* load rgctx ptr from vtable */
528 g_assert (arm_is_imm12 (G_STRUCT_OFFSET (MonoVTable
, runtime_generic_context
)));
529 ARM_LDR_IMM (code
, ARMREG_R1
, ARMREG_R0
, G_STRUCT_OFFSET (MonoVTable
, runtime_generic_context
));
530 /* is the rgctx ptr null? */
531 ARM_CMP_REG_IMM (code
, ARMREG_R1
, 0, 0);
532 /* if yes, jump to actual trampoline */
533 rgctx_null_jumps
[njumps
++] = code
;
534 ARM_B_COND (code
, ARMCOND_EQ
, 0);
537 for (i
= 0; i
< depth
; ++i
) {
538 /* load ptr to next array */
539 if (mrgctx
&& i
== 0) {
540 g_assert (arm_is_imm12 (MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT
));
541 ARM_LDR_IMM (code
, ARMREG_R1
, ARMREG_R1
, MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT
);
543 ARM_LDR_IMM (code
, ARMREG_R1
, ARMREG_R1
, 0);
545 /* is the ptr null? */
546 ARM_CMP_REG_IMM (code
, ARMREG_R1
, 0, 0);
547 /* if yes, jump to actual trampoline */
548 rgctx_null_jumps
[njumps
++] = code
;
549 ARM_B_COND (code
, ARMCOND_EQ
, 0);
553 code
= mono_arm_emit_load_imm (code
, ARMREG_R2
, sizeof (gpointer
) * (index
+ 1));
554 ARM_LDR_REG_REG (code
, ARMREG_R1
, ARMREG_R1
, ARMREG_R2
);
555 /* is the slot null? */
556 ARM_CMP_REG_IMM (code
, ARMREG_R1
, 0, 0);
557 /* if yes, jump to actual trampoline */
558 rgctx_null_jumps
[njumps
++] = code
;
559 ARM_B_COND (code
, ARMCOND_EQ
, 0);
560 /* otherwise return, result is in R1 */
561 ARM_MOV_REG_REG (code
, ARMREG_R0
, ARMREG_R1
);
562 code
= emit_bx (code
, ARMREG_LR
);
564 g_assert (njumps
<= depth
+ 2);
565 for (i
= 0; i
< njumps
; ++i
)
566 arm_patch (rgctx_null_jumps
[i
], code
);
568 g_free (rgctx_null_jumps
);
572 /* The vtable/mrgctx is still in R0 */
575 ji
= mono_patch_info_list_prepend (ji
, code
- buf
, MONO_PATCH_INFO_JIT_ICALL_ADDR
, g_strdup_printf ("specific_trampoline_lazy_fetch_%u", slot
));
576 ARM_LDR_IMM (code
, ARMREG_R1
, ARMREG_PC
, 0);
578 *(gpointer
*)code
= NULL
;
580 ARM_LDR_REG_REG (code
, ARMREG_PC
, ARMREG_PC
, ARMREG_R1
);
582 tramp
= mono_arch_create_specific_trampoline (GUINT_TO_POINTER (slot
), MONO_TRAMPOLINE_RGCTX_LAZY_FETCH
, mono_get_root_domain (), &code_len
);
584 /* Jump to the actual trampoline */
585 ARM_LDR_IMM (code
, ARMREG_R1
, ARMREG_PC
, 0); /* temp reg */
586 code
= emit_bx (code
, ARMREG_R1
);
587 *(gpointer
*)code
= tramp
;
591 mono_arch_flush_icache (buf
, code
- buf
);
593 g_assert (code
- buf
<= tramp_size
);
596 *info
= mono_tramp_info_create (g_strdup_printf ("rgctx_fetch_trampoline_%u", slot
), buf
, code
- buf
, ji
, unwind_ops
);
601 #define arm_is_imm8(v) ((v) > -256 && (v) < 256)
604 mono_arch_create_generic_class_init_trampoline (MonoTrampInfo
**info
, gboolean aot
)
608 static int byte_offset
= -1;
609 static guint8 bitmask
;
612 guint32 code_len
, imm8
;
614 GSList
*unwind_ops
= NULL
;
615 MonoJumpInfo
*ji
= NULL
;
619 code
= buf
= mono_global_codeman_reserve (tramp_size
);
622 mono_marshal_find_bitfield_offset (MonoVTable
, initialized
, &byte_offset
, &bitmask
);
624 g_assert (arm_is_imm8 (byte_offset
));
625 ARM_LDRSB_IMM (code
, ARMREG_IP
, MONO_ARCH_VTABLE_REG
, byte_offset
);
626 imm8
= mono_arm_is_rotated_imm8 (bitmask
, &rot_amount
);
627 g_assert (imm8
>= 0);
628 ARM_AND_REG_IMM (code
, ARMREG_IP
, ARMREG_IP
, imm8
, rot_amount
);
629 ARM_CMP_REG_IMM (code
, ARMREG_IP
, 0, 0);
631 ARM_B_COND (code
, ARMCOND_EQ
, 0);
633 /* Initialized case */
634 ARM_MOV_REG_REG (code
, ARMREG_PC
, ARMREG_LR
);
636 /* Uninitialized case */
637 arm_patch (jump
, code
);
640 ji
= mono_patch_info_list_prepend (ji
, code
- buf
, MONO_PATCH_INFO_JIT_ICALL_ADDR
, "specific_trampoline_generic_class_init");
641 ARM_LDR_IMM (code
, ARMREG_R1
, ARMREG_PC
, 0);
643 *(gpointer
*)code
= NULL
;
645 ARM_LDR_REG_REG (code
, ARMREG_PC
, ARMREG_PC
, ARMREG_R1
);
647 tramp
= mono_arch_create_specific_trampoline (NULL
, MONO_TRAMPOLINE_GENERIC_CLASS_INIT
, mono_get_root_domain (), &code_len
);
649 /* Jump to the actual trampoline */
650 ARM_LDR_IMM (code
, ARMREG_R1
, ARMREG_PC
, 0); /* temp reg */
651 code
= emit_bx (code
, ARMREG_R1
);
652 *(gpointer
*)code
= tramp
;
656 mono_arch_flush_icache (buf
, code
- buf
);
658 g_assert (code
- buf
<= tramp_size
);
661 *info
= mono_tramp_info_create (g_strdup_printf ("generic_class_init_trampoline"), buf
, code
- buf
, ji
, unwind_ops
);
669 mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type
, MonoTrampInfo
**info
, gboolean aot
)
671 g_assert_not_reached ();
676 mono_arch_create_specific_trampoline (gpointer arg1
, MonoTrampolineType tramp_type
, MonoDomain
*domain
, guint32
*code_len
)
678 g_assert_not_reached ();
683 mono_arch_get_unbox_trampoline (MonoGenericSharingContext
*gsctx
, MonoMethod
*m
, gpointer addr
)
685 g_assert_not_reached ();
690 mono_arch_get_static_rgctx_trampoline (MonoMethod
*m
, MonoMethodRuntimeGenericContext
*mrgctx
, gpointer addr
)
692 g_assert_not_reached ();
697 mono_arch_create_rgctx_lazy_fetch_trampoline (guint32 slot
, MonoTrampInfo
**info
, gboolean aot
)
699 g_assert_not_reached ();
704 mono_arch_create_generic_class_init_trampoline (MonoTrampInfo
**info
, gboolean aot
)
706 g_assert_not_reached ();
710 #endif /* DISABLE_JIT */
713 mono_arch_get_call_target (guint8
*code
)
715 guint32 ins
= ((guint32
*)(gpointer
)code
) [-1];
717 /* Should be a 'bl' */
718 if ((((ins
>> 25) & 0x7) == 0x5) && (((ins
>> 24) & 0x1) == 0x1)) {
719 gint32 disp
= ((gint32
)ins
) & 0xffffff;
720 guint8
*target
= code
- 4 + 8 + (disp
* 4);
729 mono_arch_get_plt_info_offset (guint8
*plt_entry
, mgreg_t
*regs
, guint8
*code
)
731 /* The offset is stored as the 4th word of the plt entry */
732 return ((guint32
*)plt_entry
) [3];