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 NOT_IMPLEMENTED(x) \
22 g_error ("FIXME: %s is not yet implemented.", x);
24 #define ALPHA_DEBUG(x) \
25 if (mini_alpha_verbose_level) \
26 g_debug ("ALPHA_DEBUG: %s is called.", x);
28 #define ALPHA_PRINT if (mini_alpha_verbose_level)
30 /*========================= End of Defines =========================*/
32 /*------------------------------------------------------------------*/
34 /*------------------------------------------------------------------*/
40 #include <mono/metadata/appdomain.h>
41 #include <mono/metadata/marshal.h>
42 #include <mono/metadata/tabledefs.h>
43 #include <mono/arch/alpha/alpha-codegen.h>
44 #include <mono/metadata/mono-debug-debugger.h>
47 #include "mini-alpha.h"
49 /*========================= End of Includes ========================*/
51 /*------------------------------------------------------------------*/
53 /*------------------------------------------------------------------*/
55 /*========================= End of Typedefs ========================*/
57 /*------------------------------------------------------------------*/
58 /* P r o t o t y p e s */
59 /*------------------------------------------------------------------*/
61 /*========================= End of Prototypes ======================*/
63 /*------------------------------------------------------------------*/
64 /* G l o b a l V a r i a b l e s */
65 /*------------------------------------------------------------------*/
68 /*====================== End of Global Variables ===================*/
70 extern int mini_alpha_verbose_level;
72 /*------------------------------------------------------------------*/
74 /* Name - mono_arch_create_trampoline_code */
76 /* Function - Create the designated type of trampoline according*/
77 /* to the 'tramp_type' parameter. */
80 This code should expect to be called by tramp stub function
82 - pv points to start of stub function
83 - at points to start of this trampoline
84 - allocate stack to save all regs and lmfs
87 - fill params for trampoline methods (They expect 4 params)
88 - call trampoline method (by standard call convention (pv + ra))
89 - save return value (r0)
90 - restore saved regs + lmfs
91 - restore stack (don't forget space allocated by stub)
92 - use saved return values as new address to give control to
93 - return or jump to new address (don't expect to return here -
94 don't save return address. RA will be holding return address
95 of original caller of tramp stub function). New address function
96 expect standart calling convention (pv)
99 /*------------------------------------------------------------------*/
102 mono_arch_create_trampoline_code (MonoTrampolineType tramp_type)
104 unsigned int *buf, *code, *tramp;
105 int i, offset, framesize, off, lmf_offset, saved_regs_offset;
106 //int saved_fpregs_offset, saved_regs_offset, method_offset, tramp_offset;
110 ALPHA_DEBUG("mono_arch_create_trampoline_code");
112 if (tramp_type == MONO_TRAMPOLINE_JUMP)
117 code = buf = mono_global_codeman_reserve (1024);
119 framesize = 1024 + sizeof (MonoLMF);
120 framesize = (framesize +
121 (MONO_ARCH_FRAME_ALIGNMENT - 1)) & ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
125 // Expect that generated code is called with 2 parameters
126 // method and tramp (in a0 and a1)
129 alpha_lda(code, alpha_sp, alpha_sp, -framesize);
131 /* store call convention parameters on stack.*/
132 alpha_stq( code, alpha_ra, alpha_sp, 0 ); // ra
133 alpha_stq( code, alpha_fp, alpha_sp, 8 ); // fp
135 saved_regs_offset = offset;
137 // Store all integer regs
138 for (i=0; i<30 /*alpha_pc*/; i++)
140 alpha_stq(code, i, alpha_sp, offset);
145 for (i=0; i<alpha_fzero; i++)
147 alpha_stt(code, i, alpha_sp, offset);
153 // Save LMF (TSV_TODO don't forget callee saved regs)
155 offset += sizeof (MonoLMF);
159 alpha_stq(code, alpha_ra, alpha_sp, (lmf_offset + G_STRUCT_OFFSET (MonoLMF, eip)));
161 alpha_stq(code, alpha_zero, alpha_sp, (lmf_offset + G_STRUCT_OFFSET (MonoLMF, eip)));
163 alpha_stq(code, alpha_fp, alpha_sp, (lmf_offset + G_STRUCT_OFFSET (MonoLMF, ebp)));
166 alpha_ldq(code, alpha_r0, alpha_sp, framesize);
167 alpha_stq(code, alpha_r0, alpha_sp, (lmf_offset + G_STRUCT_OFFSET (MonoLMF, method)));
170 alpha_lda(code, alpha_r0, alpha_sp, (framesize+16));
171 alpha_stq(code, alpha_r0, alpha_sp, (lmf_offset + G_STRUCT_OFFSET (MonoLMF, rsp)));
174 alpha_stq(code, alpha_gp, alpha_sp, (lmf_offset + G_STRUCT_OFFSET (MonoLMF, rgp)));
177 off = (char *)code - (char *)buf;
186 // alpha_at points to start of this method !!!
187 alpha_ldq(code, alpha_r0, alpha_at, off);
188 alpha_br(code, alpha_zero, 2);
190 *code = (unsigned int)(((unsigned long)mono_get_lmf_addr) & 0xFFFFFFFF);
192 *code = (unsigned int)((((unsigned long)mono_get_lmf_addr) >> 32) & 0xFFFFFFFF);
196 * The call might clobber argument registers, but they are already
197 * saved to the stack/global regs.
199 alpha_jsr(code, alpha_ra, alpha_r0, 0);
202 alpha_stq(code, alpha_r0, alpha_sp,
203 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
204 // Load "previous_lmf" member of MonoLMF struct
205 alpha_ldq(code, alpha_r1, alpha_r0, 0);
207 // Save it to MonoLMF struct
208 alpha_stq(code, alpha_r1, alpha_sp,
209 (lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
211 alpha_lda(code, alpha_r1, alpha_sp, lmf_offset);
212 alpha_stq(code, alpha_r1, alpha_r0, 0);
216 /* set the frame pointer */
217 alpha_mov1( code, alpha_sp, alpha_fp );
219 /* Arg3 is the method/vtable ptr */
220 alpha_ldq(code, alpha_a2, alpha_sp, framesize);
221 //alpha_mov1(code, alpha_a0, alpha_a2);
223 /* Arg4 is the trampoline address */
224 // Load PV from saved regs - later optimize it and load into a3 directly
225 alpha_ldq(code, alpha_pv, alpha_sp, (saved_regs_offset + (alpha_pv*8)));
226 alpha_mov1(code, alpha_pv, alpha_a3);
227 //alpha_mov1(code, alpha_a1, alpha_a3);
229 /* Arg1 is the pointer to the saved registers */
230 alpha_lda(code, alpha_a0, alpha_sp, 16);
232 alpha_ldq(code, alpha_ra, alpha_sp, (saved_regs_offset + (alpha_ra*8)));
233 /* Arg2 is the address of the calling code */
235 alpha_mov1(code, alpha_ra, alpha_a1);
237 alpha_mov1(code, alpha_zero, alpha_a1);
239 /* Arg3 is the method/vtable ptr
240 alpha_mov1(code, alpha_a0, alpha_a2);
242 Arg4 is the trampoline address
243 alpha_mov1(code, alpha_a1, alpha_a3);
246 if (tramp_type == MONO_TRAMPOLINE_CLASS_INIT)
247 tramp = (unsigned int*)mono_class_init_trampoline;
248 else if (tramp_type == MONO_TRAMPOLINE_AOT)
249 tramp = (unsigned int*)mono_aot_trampoline;
250 else if (tramp_type == MONO_TRAMPOLINE_DELEGATE)
251 tramp = (unsigned int*)mono_delegate_trampoline;
253 tramp = (unsigned int*)mono_magic_trampoline;
256 alpha_ldq(code, alpha_at, alpha_sp, (saved_regs_offset + (alpha_at*8)));
258 off = (char *)code - (char *)buf;
267 // alpha_at points to start of this method !!!
268 alpha_ldq(code, alpha_pv, alpha_at, off);
269 alpha_br(code, alpha_zero, 2);
271 *code = (unsigned int)(((unsigned long)tramp) & 0xFFFFFFFF);
273 *code = (unsigned int)((((unsigned long)tramp) >> 32) & 0xFFFFFFFF);
276 alpha_jsr(code, alpha_ra, alpha_pv, 0);
278 alpha_stq(code, alpha_r0, alpha_sp, framesize);
283 /* Restore previous lmf */
284 alpha_ldq(code, alpha_at, alpha_sp,
285 (lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf)));
286 alpha_ldq(code, alpha_ra, alpha_sp,
287 (lmf_offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr)));
288 alpha_stq(code, alpha_at, alpha_ra, 0);
293 // Restore all integer regs
294 for (i=0; i<30 /*alpha_pc*/; i++)
296 alpha_ldq(code, i, alpha_sp, offset);
300 // Restore all float regs
301 for (i=0; i<alpha_fzero; i++)
303 alpha_ldt(code, i, alpha_sp, offset);
307 alpha_ldq(code, alpha_r0, alpha_sp, framesize);
310 alpha_lda(code, alpha_sp, alpha_sp, (framesize+16));
312 if (tramp_type == MONO_TRAMPOLINE_CLASS_INIT)
313 alpha_ret (code, alpha_ra, 1);
316 /* call the compiled method */
317 // It will expect correct call frame
319 alpha_mov1(code, alpha_r0, alpha_pv);
320 alpha_jsr (code, alpha_zero, alpha_pv, 0);
323 g_assert (((char *)code - (char *)buf) <= 1024);
325 mono_arch_flush_icache ((guchar *)buf, (char *)code - (char *)buf);
327 return (guchar *)buf;
330 /*========================= End of Function ========================*/
332 /*------------------------------------------------------------------*/
334 /* Name - mono_arch_create_jit_trampoline */
336 /* Function - Creates a trampoline function for virtual methods.*/
337 /* If the created code is called it first starts JIT */
338 /* compilation and then calls the newly created */
339 /* method. It also replaces the corresponding vtable */
340 /* entry (see s390_magic_trampoline). */
342 /* A trampoline consists of two parts: a main */
343 /* fragment, shared by all method trampolines, and */
344 /* and some code specific to each method, which */
345 /* hard-codes a reference to that method and then */
346 /* calls the main fragment. */
348 /* The main fragment contains a call to */
349 /* 's390_magic_trampoline', which performs a call */
350 /* to the JIT compiler and substitutes the method- */
351 /* specific fragment with some code that directly */
352 /* calls the JIT-compiled method. */
354 /* Parameter - method - Pointer to the method information */
356 /* Returns - A pointer to the newly created code */
358 /*------------------------------------------------------------------*/
361 mono_arch_create_jit_trampoline (MonoMethod *method)
363 ALPHA_DEBUG("mono_arch_create_jit_trampoline: check MONO_ARCH_HAVE_CREATE_SPECIFIC_TRAMPOLINE define");
365 // NOT_IMPLEMENTED("mono_arch_create_jit_trampoline: check MONO_ARCH_HAVE_CREATE_SPECIFIC_TRAMPOLINE define");
370 /*========================= End of Function ========================*/
372 /*------------------------------------------------------------------*/
374 /* Name - mono_arch_create_jump_trampoline */
376 /* Function - Create the designated type of trampoline according*/
377 /* to the 'tramp_type' parameter. */
379 /*------------------------------------------------------------------*/
382 mono_arch_create_jump_trampoline (MonoMethod *method)
384 ALPHA_DEBUG("mono_arch_create_jump_trampoline");
386 NOT_IMPLEMENTED("mono_arch_create_jump_trampoline");
391 /*========================= End of Function ========================*/
393 /*------------------------------------------------------------------*/
395 /* Name - mono_arch_create_specific_trampoline */
397 /* Function - ???Create the designated type of trampoline according*/
398 /* to the 'tramp_type' parameter. */
400 /* This method should create a stub code that will transfer
401 control to corresponding trampoline. We need to pass "arg1" and
402 start address of this stab method to trampoline code.
403 We should not modify any registers!!!
405 - allocate 2 qword on stack
406 - save stab start address on 8(sp)
407 - save "arg1" on 0(sp)
408 - jump to trampoline code keeping original caller return address
411 /*------------------------------------------------------------------*/
413 #define TRAMPOLINE_SIZE 64
416 mono_arch_create_specific_trampoline (gpointer arg1,
417 MonoTrampolineType tramp_type, MonoDomain *domain, guint32 *code_len)
419 unsigned int *code, *buf, *tramp, *real_code;
420 int offset, size; //, jump_offset;
422 ALPHA_DEBUG("mono_arch_create_specific_trampoline");
424 tramp = (unsigned int *)mono_get_trampoline_code (tramp_type);
426 code = buf = g_alloca (TRAMPOLINE_SIZE);
428 /* push trampoline address */
429 //amd64_lea_membase (code, AMD64_R11, AMD64_RIP, -7);
430 //amd64_push_reg (code, AMD64_R11);
432 // Allocate two qwords on stack
433 alpha_lda(code, alpha_sp, alpha_sp, -16);
435 // Save my stub address at 8(sp)
436 alpha_stq(code, alpha_pv, alpha_sp, 8);
438 // Load arg1 into alpha_at
439 offset = (char *)code - (char *)buf;
447 alpha_ldq(code, alpha_at, alpha_pv, offset);
448 alpha_br(code, alpha_zero, 2);
450 *code = (unsigned int)(((unsigned long)arg1) & 0xFFFFFFFF);
452 *code = (unsigned int)((((unsigned long)arg1) >> 32) & 0xFFFFFFFF);
455 // Store arg1 on stack
456 alpha_stq(code, alpha_at, alpha_sp, 0);
458 offset = (char *)code - (char *)buf;
466 alpha_ldq(code, alpha_at, alpha_pv, offset);
467 alpha_br(code, alpha_zero, 2);
469 *code = (unsigned int)(((unsigned long)tramp) & 0xFFFFFFFF);
471 *code = (unsigned int)((((unsigned long)tramp) >> 32) & 0xFFFFFFFF);
474 // Jump to trampoline
475 alpha_jmp(code, alpha_zero, alpha_at, 0);
477 g_assert (((char *)code - (char *)buf) <= TRAMPOLINE_SIZE);
478 mono_domain_lock (domain);
480 * FIXME: Changing the size to code - buf causes strange crashes during
483 real_code = mono_code_manager_reserve (domain->code_mp, TRAMPOLINE_SIZE);
484 size = (char *)code - (char *)buf;
485 mono_domain_unlock (domain);
487 memcpy (real_code, buf, size);
490 g_debug("mono_arch_create_specific_trampoline: Target: %p, Arg1: %p",
493 mono_jit_stats.method_trampolines++;
498 mono_arch_flush_icache ((guchar *)real_code, size);
502 /*========================= End of Function ========================*/
505 mono_arch_nullify_class_init_trampoline (guint8 *code, gssize *regs)
507 unsigned int *pcode = (unsigned int *)code;
509 ALPHA_DEBUG("mono_arch_nullify_class_init_trampoline");
514 ** This method is called after delegate method is compiled.
515 ** We need to patch call site to call compiled method directly
516 ** (not via trampoline stub)
517 ** Determine address to patch using fp reg
522 mono_arch_patch_delegate_trampoline (guint8 *code, guint8 *tramp,
523 gssize *regs, guint8 *addr)
525 unsigned int *pcode = (unsigned int *)code;
527 short fp_disp, obj_disp;
528 unsigned long *pobj, obj;
530 ALPHA_DEBUG("mono_arch_patch_delegate_trampoline");
532 // The call signature for now is
533 // -4 - ldq v0,24(fp)
534 // -3 - ldq v0,40(v0)
536 // -1 - jsr ra,(t12),0x200041476e4
538 if (((pcode[-4] & 0xFF000000) == 0xA4000000) &&
539 ((pcode[-3] & 0xFF000000) == 0xA4000000) &&
540 ((pcode[-2] & 0xFF00FF00) == 0x47000400) &&
541 ((pcode[-1] & 0xFFFF0000) == 0x6B5B0000))
543 fp_disp = (pcode[-4] & 0xFFFF);
544 obj_disp = (pcode[-3] & 0xFFFF);
546 pobj = regs[15] + fp_disp;
551 // The non-optimized call signature for now is
552 // -5 - ldq v0,24(fp)
554 // -3 - ldq v0,40(v0)
556 // -1 - jsr ra,(t12),0x200041476e4
558 if (((pcode[-5] & 0xFF000000) == 0xA4000000) &&
559 ((pcode[-4] & 0xFF00FF00) == 0x47000400) &&
560 ((pcode[-3] & 0xFF000000) == 0xA4000000) &&
561 ((pcode[-2] & 0xFF00FF00) == 0x47000400) &&
562 ((pcode[-1] & 0xFFFF0000) == 0x6B5B0000))
564 fp_disp = (pcode[-5] & 0xFFFF);
565 obj_disp = (pcode[-3] & 0xFFFF);
567 pobj = regs[15] + fp_disp;
572 g_assert_not_reached ();
574 *((gpointer*)(obj + obj_disp)) = addr;
578 mono_arch_patch_callsite (guint8 *code, guint8 *addr)
580 unsigned long *p = (unsigned int *)(code-12);
582 unsigned int *pcode = (unsigned int *)code;
583 unsigned long gp = (unsigned long)pcode;
584 unsigned int call_addr_inst;
585 short high_offset, low_offset;
587 ALPHA_DEBUG("mono_arch_patch_callsite");
589 // Code points to the next instruction after the "jsr"
590 // In current implementation where we put jump addresses
591 // inside the code - we need to put "new" address into
594 // With new method of using GOT we need to find address
595 // where function address is stored
596 // code points to two insts:
597 // ldah gp, high_offset(ra)
598 // lda gp, low_offset(gp)
601 high_offset = *((short *)pcode);
602 low_offset = *((short *)(pcode + 1));
604 gp += 65536 * high_offset + low_offset;
606 call_addr_inst = *(pcode - 2);
608 // Check for load address instruction
609 // It should be ldq t12, offset(gp)
610 if ((call_addr_inst & 0xFFFF0000) == 0xA77D0000)
612 gp += *((short *)(pcode - 2));
614 p = (unsigned long *)gp;
616 ALPHA_PRINT g_debug("Patch callsite at %p to %p\n", p, addr);
618 // TODO - need to to interlocked update here
619 *p = (unsigned long)addr;
624 * mono_arch_get_unbox_trampoline:
626 * @addr: pointer to native code for @m
628 * when value type methods are called through the vtable we need to unbox the
629 * this argument. This method returns a pointer to a trampoline which does
630 * unboxing before calling the method
633 mono_arch_get_unbox_trampoline (MonoMethod *m, gpointer addr)
635 unsigned int *code, *start_code;
636 int this_reg = 16; //R16
638 MonoDomain *domain = mono_domain_get ();
640 ALPHA_DEBUG("mono_arch_get_unbox_trampoline");
642 if (!mono_method_signature (m)->ret->byref &&
643 MONO_TYPE_ISSTRUCT (mono_method_signature (m)->ret))
646 mono_domain_lock (domain);
647 start_code = code = (unsigned int *)mono_code_manager_reserve (domain->code_mp, 32);
648 mono_domain_unlock (domain);
650 // Adjust this by size of MonoObject
651 alpha_addq_(code, this_reg, sizeof(MonoObject), this_reg); // 0
652 alpha_bsr(code, alpha_pv, 2); // 4
654 *code = (unsigned int)(((unsigned long)addr) & 0xFFFFFFFF);
656 *code = (unsigned int)((((unsigned long)addr) >> 32) & 0xFFFFFFFF);
659 // Load "addr" into PV (R12)
660 alpha_ldq(code, alpha_pv, alpha_pv, 0);
663 alpha_jsr(code, alpha_zero, alpha_pv, 0);
665 g_assert (((char *)code - (char *)start_code) < 32);
667 mono_arch_flush_icache (start_code, (char *)code - (char *)start_code);
673 mono_arch_nullify_plt_entry (guint8 *code)
675 g_assert_not_reached ();
679 mono_arch_patch_plt_entry (guint8 *code, guint8 *addr)
681 g_assert_not_reached ();
685 * This method is only called when running in the Mono Debugger.
688 mono_debugger_create_notification_function (MonoCodeManager *codeman)
693 code = mono_code_manager_reserve (codeman, 16);
694 buf = (unsigned int *)code;
698 alpha_call_pal(buf, 0x80);
699 alpha_ret(buf, alpha_ra, 1);
700 //x86_breakpoint (buf);