1 /*------------------------------------------------------------------*/
3 /* Name - tramp-alpha.c */
5 /* Function - JIT trampoline code for Alpha. */
7 /* Name - Sergey Tikhonov (tsv@solvo.ru) */
9 /* Date - January, 2006 */
11 /* Derivation - From exceptions-amd64 & exceptions-ia64 */
12 /* Dietmar Maurer (dietmar@ximian.com) */
13 /* Zoltan Varga (vargaz@gmail.com) */
16 /*------------------------------------------------------------------*/
18 /*------------------------------------------------------------------*/
20 /*------------------------------------------------------------------*/
21 #define ALPHA_DEBUG(x) \
22 if (mini_alpha_verbose_level) \
23 g_debug ("ALPHA_DEBUG: %s is called.", x);
25 #define ALPHA_PRINT if (mini_alpha_verbose_level)
27 /*========================= End of Defines =========================*/
29 /*------------------------------------------------------------------*/
31 /*------------------------------------------------------------------*/
37 #include <mono/metadata/appdomain.h>
38 #include <mono/metadata/marshal.h>
39 #include <mono/metadata/tabledefs.h>
40 #include <mono/arch/alpha/alpha-codegen.h>
41 #include <mono/metadata/mono-debug-debugger.h>
44 #include "mini-alpha.h"
46 /*========================= End of Includes ========================*/
48 /*------------------------------------------------------------------*/
50 /*------------------------------------------------------------------*/
52 /*========================= End of Typedefs ========================*/
54 /*------------------------------------------------------------------*/
55 /* P r o t o t y p e s */
56 /*------------------------------------------------------------------*/
58 /*========================= End of Prototypes ======================*/
60 /*------------------------------------------------------------------*/
61 /* G l o b a l V a r i a b l e s */
62 /*------------------------------------------------------------------*/
65 /*====================== End of Global Variables ===================*/
67 extern int mini_alpha_verbose_level
;
69 /*------------------------------------------------------------------*/
71 /* Name - mono_arch_create_trampoline_code */
73 /* Function - Create the designated type of trampoline according*/
74 /* to the 'tramp_type' parameter. */
77 This code should expect to be called by tramp stub function
79 - pv points to start of stub function
80 - at points to start of this trampoline
81 - allocate stack to save all regs and lmfs
84 - fill params for trampoline methods (They expect 4 params)
85 - call trampoline method (by standard call convention (pv + ra))
86 - save return value (r0)
87 - restore saved regs + lmfs
88 - restore stack (don't forget space allocated by stub)
89 - use saved return values as new address to give control to
90 - return or jump to new address (don't expect to return here -
91 don't save return address. RA will be holding return address
92 of original caller of tramp stub function). New address function
93 expect standart calling convention (pv)
96 /*------------------------------------------------------------------*/
99 mono_arch_create_trampoline_code (MonoTrampolineType tramp_type
)
101 unsigned int *buf
, *code
, *tramp
;
102 int i
, offset
, framesize
, off
, lmf_offset
, saved_regs_offset
;
103 //int saved_fpregs_offset, saved_regs_offset, method_offset, tramp_offset;
107 ALPHA_DEBUG("mono_arch_create_trampoline_code");
109 if (tramp_type
== MONO_TRAMPOLINE_JUMP
)
114 code
= buf
= mono_global_codeman_reserve (1024);
116 framesize
= 1024 + sizeof (MonoLMF
);
117 framesize
= (framesize
+
118 (MONO_ARCH_FRAME_ALIGNMENT
- 1)) & ~(MONO_ARCH_FRAME_ALIGNMENT
- 1);
122 // Expect that generated code is called with 2 parameters
123 // method and tramp (in a0 and a1)
126 alpha_lda(code
, alpha_sp
, alpha_sp
, -framesize
);
128 /* store call convention parameters on stack.*/
129 alpha_stq( code
, alpha_ra
, alpha_sp
, 0 ); // ra
130 alpha_stq( code
, alpha_fp
, alpha_sp
, 8 ); // fp
132 saved_regs_offset
= offset
;
134 // Store all integer regs
135 for (i
=0; i
<30 /*alpha_pc*/; i
++)
137 alpha_stq(code
, i
, alpha_sp
, offset
);
142 for (i
=0; i
<alpha_fzero
; i
++)
144 alpha_stt(code
, i
, alpha_sp
, offset
);
150 // Save LMF (TSV_TODO don't forget callee saved regs)
152 offset
+= sizeof (MonoLMF
);
156 alpha_stq(code
, alpha_ra
, alpha_sp
, (lmf_offset
+ G_STRUCT_OFFSET (MonoLMF
, eip
)));
158 alpha_stq(code
, alpha_zero
, alpha_sp
, (lmf_offset
+ G_STRUCT_OFFSET (MonoLMF
, eip
)));
160 alpha_stq(code
, alpha_fp
, alpha_sp
, (lmf_offset
+ G_STRUCT_OFFSET (MonoLMF
, ebp
)));
163 alpha_ldq(code
, alpha_r0
, alpha_sp
, framesize
);
164 alpha_stq(code
, alpha_r0
, alpha_sp
, (lmf_offset
+ G_STRUCT_OFFSET (MonoLMF
, method
)));
167 alpha_lda(code
, alpha_r0
, alpha_sp
, (framesize
+16));
168 alpha_stq(code
, alpha_r0
, alpha_sp
, (lmf_offset
+ G_STRUCT_OFFSET (MonoLMF
, rsp
)));
171 alpha_stq(code
, alpha_gp
, alpha_sp
, (lmf_offset
+ G_STRUCT_OFFSET (MonoLMF
, rgp
)));
174 off
= (char *)code
- (char *)buf
;
183 // alpha_at points to start of this method !!!
184 alpha_ldq(code
, alpha_pv
, alpha_at
, off
);
185 alpha_br(code
, alpha_zero
, 2);
187 *code
= (unsigned int)(((unsigned long)mono_get_lmf_addr
) & 0xFFFFFFFF);
189 *code
= (unsigned int)((((unsigned long)mono_get_lmf_addr
) >> 32) & 0xFFFFFFFF);
193 * The call might clobber argument registers, but they are already
194 * saved to the stack/global regs.
196 alpha_jsr(code
, alpha_ra
, alpha_pv
, 0);
199 alpha_stq(code
, alpha_r0
, alpha_sp
,
200 (lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, lmf_addr
)));
201 // Load "previous_lmf" member of MonoLMF struct
202 alpha_ldq(code
, alpha_r1
, alpha_r0
, 0);
204 // Save it to MonoLMF struct
205 alpha_stq(code
, alpha_r1
, alpha_sp
,
206 (lmf_offset
+ G_STRUCT_OFFSET(MonoLMF
, previous_lmf
)));
208 alpha_lda(code
, alpha_r1
, alpha_sp
, lmf_offset
);
209 alpha_stq(code
, alpha_r1
, alpha_r0
, 0);
213 /* set the frame pointer */
214 alpha_mov1( code
, alpha_sp
, alpha_fp
);
216 /* Arg3 is the method/vtable ptr */
217 alpha_ldq(code
, alpha_a2
, alpha_sp
, framesize
);
218 //alpha_mov1(code, alpha_a0, alpha_a2);
220 /* Arg4 is the trampoline address */
221 // Load PV from saved regs - later optimize it and load into a3 directly
222 alpha_ldq(code
, alpha_pv
, alpha_sp
, (saved_regs_offset
+ (alpha_pv
*8)));
223 alpha_mov1(code
, alpha_pv
, alpha_a3
);
224 //alpha_mov1(code, alpha_a1, alpha_a3);
226 /* Arg1 is the pointer to the saved registers */
227 alpha_lda(code
, alpha_a0
, alpha_sp
, 16);
229 alpha_ldq(code
, alpha_ra
, alpha_sp
, (saved_regs_offset
+ (alpha_ra
*8)));
230 /* Arg2 is the address of the calling code */
232 alpha_mov1(code
, alpha_ra
, alpha_a1
);
234 alpha_mov1(code
, alpha_zero
, alpha_a1
);
236 /* Arg3 is the method/vtable ptr
237 alpha_mov1(code, alpha_a0, alpha_a2);
239 Arg4 is the trampoline address
240 alpha_mov1(code, alpha_a1, alpha_a3);
243 if (tramp_type
== MONO_TRAMPOLINE_CLASS_INIT
)
244 tramp
= (unsigned int*)mono_class_init_trampoline
;
245 else if (tramp_type
== MONO_TRAMPOLINE_AOT
)
246 tramp
= (unsigned int*)mono_aot_trampoline
;
247 else if (tramp_type
== MONO_TRAMPOLINE_DELEGATE
)
248 tramp
= (unsigned int*)mono_delegate_trampoline
;
250 tramp
= (unsigned int*)mono_magic_trampoline
;
253 alpha_ldq(code
, alpha_at
, alpha_sp
, (saved_regs_offset
+ (alpha_at
*8)));
255 off
= (char *)code
- (char *)buf
;
264 // alpha_at points to start of this method !!!
265 alpha_ldq(code
, alpha_pv
, alpha_at
, off
);
266 alpha_br(code
, alpha_zero
, 2);
268 *code
= (unsigned int)(((unsigned long)tramp
) & 0xFFFFFFFF);
270 *code
= (unsigned int)((((unsigned long)tramp
) >> 32) & 0xFFFFFFFF);
273 alpha_jsr(code
, alpha_ra
, alpha_pv
, 0);
275 alpha_stq(code
, alpha_r0
, alpha_sp
, framesize
);
280 /* Restore previous lmf */
281 alpha_ldq(code
, alpha_at
, alpha_sp
,
282 (lmf_offset
+ G_STRUCT_OFFSET (MonoLMF
, previous_lmf
)));
283 alpha_ldq(code
, alpha_ra
, alpha_sp
,
284 (lmf_offset
+ G_STRUCT_OFFSET (MonoLMF
, lmf_addr
)));
285 alpha_stq(code
, alpha_at
, alpha_ra
, 0);
290 // Restore all integer regs
291 for (i
=0; i
<30 /*alpha_pc*/; i
++)
293 alpha_ldq(code
, i
, alpha_sp
, offset
);
297 // Restore all float regs
298 for (i
=0; i
<alpha_fzero
; i
++)
300 alpha_ldt(code
, i
, alpha_sp
, offset
);
304 alpha_ldq(code
, alpha_r0
, alpha_sp
, framesize
);
307 alpha_lda(code
, alpha_sp
, alpha_sp
, (framesize
+16));
309 if (tramp_type
== MONO_TRAMPOLINE_CLASS_INIT
)
310 alpha_ret (code
, alpha_ra
, 1);
313 /* call the compiled method */
314 // It will expect correct call frame
316 alpha_mov1(code
, alpha_r0
, alpha_pv
);
317 alpha_jsr (code
, alpha_zero
, alpha_pv
, 0);
320 g_assert (((char *)code
- (char *)buf
) <= 1024);
322 mono_arch_flush_icache ((guchar
*)buf
, (char *)code
- (char *)buf
);
324 return (guchar
*)buf
;
327 /*========================= End of Function ========================*/
329 /*------------------------------------------------------------------*/
331 /* Name - mono_arch_create_jit_trampoline */
333 /* Function - Creates a trampoline function for virtual methods.*/
334 /* If the created code is called it first starts JIT */
335 /* compilation and then calls the newly created */
336 /* method. It also replaces the corresponding vtable */
337 /* entry (see s390_magic_trampoline). */
339 /* A trampoline consists of two parts: a main */
340 /* fragment, shared by all method trampolines, and */
341 /* and some code specific to each method, which */
342 /* hard-codes a reference to that method and then */
343 /* calls the main fragment. */
345 /* The main fragment contains a call to */
346 /* 's390_magic_trampoline', which performs a call */
347 /* to the JIT compiler and substitutes the method- */
348 /* specific fragment with some code that directly */
349 /* calls the JIT-compiled method. */
351 /* Parameter - method - Pointer to the method information */
353 /* Returns - A pointer to the newly created code */
355 /*------------------------------------------------------------------*/
358 mono_arch_create_jit_trampoline (MonoMethod
*method
)
360 ALPHA_DEBUG("mono_arch_create_jit_trampoline: check MONO_ARCH_HAVE_CREATE_SPECIFIC_TRAMPOLINE define");
362 // NOT_IMPLEMENTED("mono_arch_create_jit_trampoline: check MONO_ARCH_HAVE_CREATE_SPECIFIC_TRAMPOLINE define");
367 /*========================= End of Function ========================*/
369 /*------------------------------------------------------------------*/
371 /* Name - mono_arch_create_jump_trampoline */
373 /* Function - Create the designated type of trampoline according*/
374 /* to the 'tramp_type' parameter. */
376 /*------------------------------------------------------------------*/
379 mono_arch_create_jump_trampoline (MonoMethod
*method
)
381 ALPHA_DEBUG("mono_arch_create_jump_trampoline");
388 /*========================= End of Function ========================*/
390 /*------------------------------------------------------------------*/
392 /* Name - mono_arch_create_specific_trampoline */
394 /* Function - ???Create the designated type of trampoline according*/
395 /* to the 'tramp_type' parameter. */
397 /* This method should create a stub code that will transfer
398 control to corresponding trampoline. We need to pass "arg1" and
399 start address of this stab method to trampoline code.
400 We should not modify any registers!!!
402 - allocate 2 qword on stack
403 - save stab start address on 8(sp)
404 - save "arg1" on 0(sp)
405 - jump to trampoline code keeping original caller return address
408 /*------------------------------------------------------------------*/
410 #define TRAMPOLINE_SIZE 64
413 mono_arch_create_specific_trampoline (gpointer arg1
,
414 MonoTrampolineType tramp_type
, MonoDomain
*domain
, guint32
*code_len
)
416 unsigned int *code
, *buf
, *tramp
, *real_code
;
417 int offset
, size
; //, jump_offset;
419 ALPHA_DEBUG("mono_arch_create_specific_trampoline");
421 tramp
= (unsigned int *)mono_get_trampoline_code (tramp_type
);
423 code
= buf
= g_alloca (TRAMPOLINE_SIZE
);
425 /* push trampoline address */
426 //amd64_lea_membase (code, AMD64_R11, AMD64_RIP, -7);
427 //amd64_push_reg (code, AMD64_R11);
429 // Allocate two qwords on stack
430 alpha_lda(code
, alpha_sp
, alpha_sp
, -16);
432 // Save my stub address at 8(sp)
433 alpha_stq(code
, alpha_pv
, alpha_sp
, 8);
435 // Load arg1 into alpha_at
436 offset
= (char *)code
- (char *)buf
;
444 alpha_ldq(code
, alpha_at
, alpha_pv
, offset
);
445 alpha_br(code
, alpha_zero
, 2);
447 *code
= (unsigned int)(((unsigned long)arg1
) & 0xFFFFFFFF);
449 *code
= (unsigned int)((((unsigned long)arg1
) >> 32) & 0xFFFFFFFF);
452 // Store arg1 on stack
453 alpha_stq(code
, alpha_at
, alpha_sp
, 0);
455 offset
= (char *)code
- (char *)buf
;
463 alpha_ldq(code
, alpha_at
, alpha_pv
, offset
);
464 alpha_br(code
, alpha_zero
, 2);
466 *code
= (unsigned int)(((unsigned long)tramp
) & 0xFFFFFFFF);
468 *code
= (unsigned int)((((unsigned long)tramp
) >> 32) & 0xFFFFFFFF);
471 // Jump to trampoline
472 alpha_jmp(code
, alpha_zero
, alpha_at
, 0);
474 g_assert (((char *)code
- (char *)buf
) <= TRAMPOLINE_SIZE
);
476 * FIXME: Changing the size to code - buf causes strange crashes during
479 real_code
= mono_domain_code_reserve (domain
, TRAMPOLINE_SIZE
);
480 size
= (char *)code
- (char *)buf
;
482 memcpy (real_code
, buf
, size
);
485 g_debug("mono_arch_create_specific_trampoline: Target: %p, Arg1: %p",
491 mono_arch_flush_icache ((guchar
*)real_code
, size
);
495 /*========================= End of Function ========================*/
498 mono_arch_nullify_class_init_trampoline (guint8
*code
, mgreg_t
*regs
)
500 unsigned int *pcode
= (unsigned int *)code
;
502 ALPHA_DEBUG("mono_arch_nullify_class_init_trampoline");
504 // pcode[-2] ldq t12,n(gp)
505 // pcode[-1] jsr ra,(t12),0x20003efcb40
506 if ((pcode
[-2] & 0xFFFF0000) == 0xa77d0000 &&
507 pcode
[-1] == 0x6b5b4000)
509 // Put "unop" into call inst
515 mono_arch_flush_icache ((code
-4), 3*4);
518 g_assert_not_reached ();
522 mono_arch_patch_callsite (guint8
*method_start
, guint8
*code
, guint8
*addr
)
524 unsigned long *p
= (unsigned int *)(code
-12);
526 unsigned int *pcode
= (unsigned int *)code
;
527 unsigned long gp
= (unsigned long)pcode
;
528 unsigned int call_addr_inst
;
529 short high_offset
, low_offset
;
531 ALPHA_DEBUG("mono_arch_patch_callsite");
533 // Code points to the next instruction after the "jsr"
534 // In current implementation where we put jump addresses
535 // inside the code - we need to put "new" address into
538 // With new method of using GOT we need to find address
539 // where function address is stored
540 // code points to two insts:
541 // ldah gp, high_offset(ra)
542 // lda gp, low_offset(gp)
545 high_offset
= *((short *)pcode
);
546 low_offset
= *((short *)(pcode
+ 1));
548 gp
+= 65536 * high_offset
+ low_offset
;
550 call_addr_inst
= *(pcode
- 2);
552 // Check for load address instruction
553 // It should be ldq t12, offset(gp)
554 if ((call_addr_inst
& 0xFFFF0000) == 0xA77D0000)
556 gp
+= *((short *)(pcode
- 2));
558 p
= (unsigned long *)gp
;
560 ALPHA_PRINT
g_debug("Patch callsite at %p to %p\n", p
, addr
);
562 // TODO - need to to interlocked update here
563 *p
= (unsigned long)addr
;
568 * mono_arch_get_unbox_trampoline:
569 * @gsctx: the generic sharing context
571 * @addr: pointer to native code for @m
573 * when value type methods are called through the vtable we need to unbox the
574 * this argument. This method returns a pointer to a trampoline which does
575 * unboxing before calling the method
578 mono_arch_get_unbox_trampoline (MonoGenericSharingContext
*gsctx
, MonoMethod
*m
, gpointer addr
)
580 unsigned int *code
, *start_code
;
581 int this_reg
= 16; //R16
583 MonoDomain
*domain
= mono_domain_get ();
585 ALPHA_DEBUG("mono_arch_get_unbox_trampoline");
587 if (MONO_TYPE_ISSTRUCT (mono_method_signature (m
)->ret
))
590 start_code
= code
= (unsigned int *)mono_domain_code_reserve (domain
, 32);
592 // Adjust this by size of MonoObject
593 alpha_addq_(code
, this_reg
, sizeof(MonoObject
), this_reg
); // 0
594 alpha_bsr(code
, alpha_pv
, 2); // 4
596 *code
= (unsigned int)(((unsigned long)addr
) & 0xFFFFFFFF);
598 *code
= (unsigned int)((((unsigned long)addr
) >> 32) & 0xFFFFFFFF);
601 // Load "addr" into PV (R12)
602 alpha_ldq(code
, alpha_pv
, alpha_pv
, 0);
605 alpha_jsr(code
, alpha_zero
, alpha_pv
, 0);
607 g_assert (((char *)code
- (char *)start_code
) < 32);
609 mono_arch_flush_icache (start_code
, (char *)code
- (char *)start_code
);
615 mono_arch_nullify_plt_entry (guint8
*code
, mgreg_t
*regs
)
617 g_assert_not_reached ();
621 mono_arch_patch_plt_entry (guint8
*code
, gpointer
*got
, mgreg_t
*regs
, guint8
*addr
)
623 g_assert_not_reached ();
627 mono_arch_create_rgctx_lazy_fetch_trampoline (guint32 encoded_offset
)
629 /* FIXME: implement! */
630 g_assert_not_reached ();