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");
515 mono_arch_patch_delegate_trampoline (guint8 *code, guint8 *tramp,
516 gssize *regs, guint8 *addr)
518 ALPHA_DEBUG("mono_arch_patch_delegate_trampoline");
522 mono_arch_patch_callsite (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:
570 * @addr: pointer to native code for @m
572 * when value type methods are called through the vtable we need to unbox the
573 * this argument. This method returns a pointer to a trampoline which does
574 * unboxing before calling the method
577 mono_arch_get_unbox_trampoline (MonoMethod *m, gpointer addr)
579 unsigned int *code, *start_code;
580 int this_reg = 16; //R16
582 MonoDomain *domain = mono_domain_get ();
584 ALPHA_DEBUG("mono_arch_get_unbox_trampoline");
586 if (!mono_method_signature (m)->ret->byref &&
587 MONO_TYPE_ISSTRUCT (mono_method_signature (m)->ret))
590 mono_domain_lock (domain);
591 start_code = code = (unsigned int *)mono_code_manager_reserve (domain->code_mp, 32);
592 mono_domain_unlock (domain);
594 // Adjust this by size of MonoObject
595 alpha_addq_(code, this_reg, sizeof(MonoObject), this_reg); // 0
596 alpha_bsr(code, alpha_pv, 2); // 4
598 *code = (unsigned int)(((unsigned long)addr) & 0xFFFFFFFF);
600 *code = (unsigned int)((((unsigned long)addr) >> 32) & 0xFFFFFFFF);
603 // Load "addr" into PV (R12)
604 alpha_ldq(code, alpha_pv, alpha_pv, 0);
607 alpha_jsr(code, alpha_zero, alpha_pv, 0);
609 g_assert (((char *)code - (char *)start_code) < 32);
611 mono_arch_flush_icache (start_code, (char *)code - (char *)start_code);
617 mono_arch_nullify_plt_entry (guint8 *code)
619 g_assert_not_reached ();
623 mono_arch_patch_plt_entry (guint8 *code, guint8 *addr)
625 g_assert_not_reached ();
629 * This method is only called when running in the Mono Debugger.
632 mono_debugger_create_notification_function (MonoCodeManager *codeman)
637 code = mono_code_manager_reserve (codeman, 16);
638 buf = (unsigned int *)code;
642 alpha_call_pal(buf, 0x80);
643 alpha_ret(buf, alpha_ra, 1);
644 //x86_breakpoint (buf);