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 g_debug ("ALPHA_DEBUG: %s is called.", x);
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 /*------------------------------------------------------------------*/
69 /* Name - mono_arch_create_trampoline_code */
71 /* Function - Create the designated type of trampoline according*/
72 /* to the 'tramp_type' parameter. */
75 This code should expect to be called by tramp stub function
77 - pv points to start of stub function
78 - at points to start of this trampoline
79 - allocate stack to save all regs and lmfs
81 - fill params for trampoline methods (They expect 4 params)
82 - call trampoline method (by standard call convention (pv + ra))
83 - save return value (r0)
84 - restore saved regs + lmfs
85 - restore stack (don't forget space allocated by stub)
86 - use saved return values as new address to give control to
87 - return or jump to new address (don't expect to return here -
88 don't save return address. RA will be holding return address
89 of original caller of tramp stub function). New address function
90 expect standart calling convention (pv)
93 /*------------------------------------------------------------------*/
96 mono_arch_create_trampoline_code (MonoTrampolineType tramp_type)
98 unsigned int *buf, *code, *tramp;
99 int i, lmf_offset, offset, method_offset, tramp_offset,
100 saved_regs_offset, saved_fpregs_offset, framesize, off;
103 ALPHA_DEBUG("mono_arch_create_trampoline_code");
105 if (tramp_type == MONO_TRAMPOLINE_JUMP)
110 code = buf = mono_global_codeman_reserve (512);
112 framesize = 512 + sizeof (MonoLMF);
113 framesize = (framesize +
114 (MONO_ARCH_FRAME_ALIGNMENT - 1)) & ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
118 // Expect that generated code is called with 2 parameters
119 // method and tramp (in a0 and a1)
122 alpha_lda(code, alpha_sp, alpha_sp, -framesize);
124 /* store call convention parameters on stack.*/
125 alpha_stq( code, alpha_ra, alpha_sp, 0 ); // ra
126 alpha_stq( code, alpha_fp, alpha_sp, 8 ); // fp
128 // Store all integer regs
129 for (i=0; i<30 /*alpha_pc*/; i++)
131 alpha_stq(code, i, alpha_sp, offset);
135 // Store all fp regs (TODO)
137 /* set the frame pointer */
138 alpha_mov1( code, alpha_sp, alpha_fp );
140 /* Arg3 is the method/vtable ptr */
141 alpha_ldq(code, alpha_a2, alpha_sp, framesize);
142 //alpha_mov1(code, alpha_a0, alpha_a2);
144 /* Arg4 is the trampoline address */
145 alpha_mov1(code, alpha_pv, alpha_a3);
146 //alpha_mov1(code, alpha_a1, alpha_a3);
148 /* Arg1 is the pointer to the saved registers */
149 alpha_lda(code, alpha_a0, alpha_sp, 16);
151 /* Arg2 is the address of the calling code */
153 alpha_mov1(code, alpha_ra, alpha_a1);
155 alpha_mov1(code, alpha_zero, alpha_a1);
157 /* Arg3 is the method/vtable ptr
158 alpha_mov1(code, alpha_a0, alpha_a2);
160 Arg4 is the trampoline address
161 alpha_mov1(code, alpha_a1, alpha_a3);
164 if (tramp_type == MONO_TRAMPOLINE_CLASS_INIT)
165 tramp = (unsigned int*)mono_class_init_trampoline;
166 else if (tramp_type == MONO_TRAMPOLINE_AOT)
167 tramp = (unsigned int*)mono_aot_trampoline;
168 else if (tramp_type == MONO_TRAMPOLINE_DELEGATE)
169 tramp = (unsigned int*)mono_delegate_trampoline;
171 tramp = (unsigned int*)mono_magic_trampoline;
173 off = (char *)code - (char *)buf;
182 // alpha_at points to start of this method !!!
183 alpha_ldq(code, alpha_pv, alpha_at, off);
184 alpha_br(code, alpha_zero, 2);
186 *code = (unsigned int)(((unsigned long)tramp) & 0xFFFFFFFF);
188 *code = (unsigned int)((((unsigned long)tramp) >> 32) & 0xFFFFFFFF);
191 alpha_jsr(code, alpha_ra, alpha_pv, 0);
193 alpha_stq(code, alpha_r0, alpha_sp, framesize);
199 // Restore all integer regs
200 for (i=0; i<30 /*alpha_pc*/; i++)
202 alpha_ldq(code, i, alpha_sp, offset);
206 alpha_ldq(code, alpha_r0, alpha_sp, framesize);
209 alpha_lda(code, alpha_sp, alpha_sp, framesize+16);
211 if (tramp_type == MONO_TRAMPOLINE_CLASS_INIT)
212 alpha_ret (code, alpha_ra, 1);
215 /* call the compiled method */
216 // It will expect correct call frame
218 alpha_mov1(code, alpha_r0, alpha_pv);
219 alpha_jsr (code, alpha_zero, alpha_pv, 0);
222 g_assert (((char *)code - (char *)buf) <= 512);
224 mono_arch_flush_icache (buf, (char *)code - (char *)buf);
229 /*========================= End of Function ========================*/
231 /*------------------------------------------------------------------*/
233 /* Name - mono_arch_create_jit_trampoline */
235 /* Function - Creates a trampoline function for virtual methods.*/
236 /* If the created code is called it first starts JIT */
237 /* compilation and then calls the newly created */
238 /* method. It also replaces the corresponding vtable */
239 /* entry (see s390_magic_trampoline). */
241 /* A trampoline consists of two parts: a main */
242 /* fragment, shared by all method trampolines, and */
243 /* and some code specific to each method, which */
244 /* hard-codes a reference to that method and then */
245 /* calls the main fragment. */
247 /* The main fragment contains a call to */
248 /* 's390_magic_trampoline', which performs a call */
249 /* to the JIT compiler and substitutes the method- */
250 /* specific fragment with some code that directly */
251 /* calls the JIT-compiled method. */
253 /* Parameter - method - Pointer to the method information */
255 /* Returns - A pointer to the newly created code */
257 /*------------------------------------------------------------------*/
260 mono_arch_create_jit_trampoline (MonoMethod *method)
262 ALPHA_DEBUG("mono_arch_create_jit_trampoline: check MONO_ARCH_HAVE_CREATE_SPECIFIC_TRAMPOLINE define");
264 // NOT_IMPLEMENTED("mono_arch_create_jit_trampoline: check MONO_ARCH_HAVE_CREATE_SPECIFIC_TRAMPOLINE define");
269 /*========================= End of Function ========================*/
271 /*------------------------------------------------------------------*/
273 /* Name - mono_arch_create_jump_trampoline */
275 /* Function - Create the designated type of trampoline according*/
276 /* to the 'tramp_type' parameter. */
278 /*------------------------------------------------------------------*/
281 mono_arch_create_jump_trampoline (MonoMethod *method)
283 ALPHA_DEBUG("mono_arch_create_jump_trampoline");
285 NOT_IMPLEMENTED("mono_arch_create_jump_trampoline");
290 /*========================= End of Function ========================*/
292 /*------------------------------------------------------------------*/
294 /* Name - mono_arch_create_specific_trampoline */
296 /* Function - ???Create the designated type of trampoline according*/
297 /* to the 'tramp_type' parameter. */
299 /* This method should create a stub code that will transfer
300 control to corresponding trampoline. We need to pass "arg1" and
301 start address of this stab method to trampoline code.
302 We should not modify any registers!!!
304 - allocate 2 qword on stack
305 - save stab start address on 8(sp)
306 - save "arg1" on 0(sp)
307 - jump to trampoline code keeping original caller return address
310 /*------------------------------------------------------------------*/
312 #define TRAMPOLINE_SIZE 52
315 mono_arch_create_specific_trampoline (gpointer arg1,
316 MonoTrampolineType tramp_type, MonoDomain *domain, guint32 *code_len)
318 unsigned int *code, *buf, *tramp, *real_code;
319 int offset, size, jump_offset;
321 // ALPHA_DEBUG("mono_arch_create_specific_trampoline");
323 tramp = mono_get_trampoline_code (tramp_type);
325 code = buf = g_alloca (TRAMPOLINE_SIZE);
327 /* push trampoline address */
328 //amd64_lea_membase (code, AMD64_R11, AMD64_RIP, -7);
329 //amd64_push_reg (code, AMD64_R11);
331 // Allocate two qwords on stack
332 alpha_lda(code, alpha_sp, alpha_sp, -16);
334 alpha_stq(code, alpha_pv, alpha_sp, 8);
336 // Load arg1 into alpha_at
337 offset = (char *)code - (char *)buf;
345 alpha_ldq(code, alpha_at, alpha_pv, offset);
346 alpha_br(code, alpha_zero, 2);
348 *code = (unsigned int)(((unsigned long)arg1) & 0xFFFFFFFF);
350 *code = (unsigned int)((((unsigned long)arg1) >> 32) & 0xFFFFFFFF);
353 // Store arg1 on stack
354 alpha_stq(code, alpha_at, alpha_sp, 0);
356 offset = (char *)code - (char *)buf;
364 alpha_ldq(code, alpha_at, alpha_pv, offset);
365 alpha_br(code, alpha_zero, 2);
367 *code = (unsigned int)(((unsigned long)tramp) & 0xFFFFFFFF);
369 *code = (unsigned int)((((unsigned long)tramp) >> 32) & 0xFFFFFFFF);
372 // Jump to trampoline
373 alpha_jmp(code, alpha_zero, alpha_at, 0);
377 //if (amd64_is_imm32 ((gint64)arg1))
378 // amd64_push_imm (code, (gint64)arg1);
380 // amd64_mov_reg_imm (code, AMD64_R11, arg1);
381 // amd64_push_reg (code, AMD64_R11);
384 // jump_offset = code - buf;
385 //amd64_jump_disp (code, 0xffffffff);
387 g_assert (((char *)code - (char *)buf) <= TRAMPOLINE_SIZE);
388 mono_domain_lock (domain);
390 * FIXME: Changing the size to code - buf causes strange crashes during
393 real_code = mono_code_manager_reserve (domain->code_mp, TRAMPOLINE_SIZE);
394 size = (char *)code - (char *)buf;
395 mono_domain_unlock (domain);
397 memcpy (real_code, buf, size);
399 printf("mono_arch_create_specific_trampoline: Target: %p, Arg1: %p\n",
403 //g_assert ((((gint64)tramp) >> 32) == 0);
404 //code = (guint8*)real_code + jump_offset;
405 //amd64_jump_disp (code, tramp - code);
407 mono_jit_stats.method_trampolines++;
412 mono_arch_flush_icache (real_code, size);
416 /*========================= End of Function ========================*/
419 mono_arch_nullify_class_init_trampoline (guint8 *code, gssize *regs)
421 ALPHA_DEBUG("mono_arch_nullify_class_init_trampoline");
426 mono_arch_patch_delegate_trampoline (guint8 *code, guint8 *tramp,
427 gssize *regs, guint8 *addr)
429 ALPHA_DEBUG("mono_arch_patch_delegate_trampoline");
433 mono_arch_patch_callsite (guint8 *code, guint8 *addr)
435 unsigned long *p = (unsigned int *)(code-12);
437 unsigned int *pcode = (unsigned int *)code;
438 unsigned long gp = pcode;
439 unsigned int call_addr_inst;
440 short high_offset, low_offset;
442 ALPHA_DEBUG("mono_arch_patch_callsite");
444 // Code points to the next instruction after the "jsr"
445 // In current implementation where we put jump addresses
446 // inside the code - we need to put "new" address into
449 // With new method of using GOT we need to find address
450 // where function address is stored
451 // code points to two insts:
452 // ldah gp, high_offset(ra)
453 // lda gp, low_offset(gp)
456 high_offset = *((short *)pcode);
457 low_offset = *((short *)(pcode + 1));
459 gp += 65536 * high_offset + low_offset;
461 call_addr_inst = *(pcode - 2);
463 // Check for load address instruction
464 // It should be ldq t12, offset(gp)
465 if ((call_addr_inst & 0xFFFF0000) == 0xA77D0000)
467 gp += *((short *)(pcode - 2));
471 printf("Patch callsite at %p to %p\n", p, addr);
473 // TODO - need to to interlocked update here
474 *p = (unsigned long)addr;
479 * mono_arch_get_unbox_trampoline:
481 * @addr: pointer to native code for @m
483 * when value type methods are called through the vtable we need to unbox the
484 * this argument. This method returns a pointer to a trampoline which does
485 * unboxing before calling the method
488 mono_arch_get_unbox_trampoline (MonoMethod *m, gpointer addr)
490 ALPHA_DEBUG("mono_arch_get_unbox_trampoline");
496 mono_arch_nullify_plt_entry (guint8 *code)
498 g_assert_not_reached ();
502 mono_arch_patch_plt_entry (guint8 *code, guint8 *addr)
504 g_assert_not_reached ();