2010-04-06 Rodrigo Kumpera <rkumpera@novell.com>
[mono.git] / mono / mini / tramp-alpha.c
blob186d9bc08cbe791bed96028e04dcf2857ba3f0af
1 /*------------------------------------------------------------------*/
2 /* */
3 /* Name - tramp-alpha.c */
4 /* */
5 /* Function - JIT trampoline code for Alpha. */
6 /* */
7 /* Name - Sergey Tikhonov (tsv@solvo.ru) */
8 /* */
9 /* Date - January, 2006 */
10 /* */
11 /* Derivation - From exceptions-amd64 & exceptions-ia64 */
12 /* Dietmar Maurer (dietmar@ximian.com) */
13 /* Zoltan Varga (vargaz@gmail.com) */
14 /* */
15 /* */
16 /*------------------------------------------------------------------*/
18 /*------------------------------------------------------------------*/
19 /* D e f i n e s */
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 /*------------------------------------------------------------------*/
30 /* I n c l u d e s */
31 /*------------------------------------------------------------------*/
33 #include <config.h>
34 #include <glib.h>
35 #include <string.h>
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>
43 #include "mini.h"
44 #include "mini-alpha.h"
46 /*========================= End of Includes ========================*/
48 /*------------------------------------------------------------------*/
49 /* T y p e d e f s */
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 /*------------------------------------------------------------------*/
70 /* */
71 /* Name - mono_arch_create_trampoline_code */
72 /* */
73 /* Function - Create the designated type of trampoline according*/
74 /* to the 'tramp_type' parameter. */
75 /* */
77 This code should expect to be called by tramp stub function
78 On Alpha:
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
82 - save regs
83 - save lmf
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 /*------------------------------------------------------------------*/
98 guchar *
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;
105 gboolean has_caller;
107 ALPHA_DEBUG("mono_arch_create_trampoline_code");
109 if (tramp_type == MONO_TRAMPOLINE_JUMP)
110 has_caller = FALSE;
111 else
112 has_caller = TRUE;
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);
120 offset = 16;
122 // Expect that generated code is called with 2 parameters
123 // method and tramp (in a0 and a1)
125 // Allocate stack
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);
138 offset += 8;
141 // Store all fp regs
142 for (i=0; i<alpha_fzero; i++)
144 alpha_stt(code, i, alpha_sp, offset);
145 offset += 8;
148 if (1)
150 // Save LMF (TSV_TODO don't forget callee saved regs)
151 lmf_offset = offset;
152 offset += sizeof (MonoLMF);
154 // Save PC
155 if (has_caller)
156 alpha_stq(code, alpha_ra, alpha_sp, (lmf_offset + G_STRUCT_OFFSET (MonoLMF, eip)));
157 else
158 alpha_stq(code, alpha_zero, alpha_sp, (lmf_offset + G_STRUCT_OFFSET (MonoLMF, eip)));
159 // Save FP
160 alpha_stq(code, alpha_fp, alpha_sp, (lmf_offset + G_STRUCT_OFFSET (MonoLMF, ebp)));
162 // Save method
163 alpha_ldq(code, alpha_r0, alpha_sp, framesize);
164 alpha_stq(code, alpha_r0, alpha_sp, (lmf_offset + G_STRUCT_OFFSET (MonoLMF, method)));
166 // Save SP
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)));
170 // Save GP
171 alpha_stq(code, alpha_gp, alpha_sp, (lmf_offset + G_STRUCT_OFFSET (MonoLMF, rgp)));
173 // Get "lmf_addr"
174 off = (char *)code - (char *)buf;
175 off += 2*4;
177 if (off % 8)
179 alpha_nop(code);
180 off += 4;
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);
188 code++;
189 *code = (unsigned int)((((unsigned long)mono_get_lmf_addr) >> 32) & 0xFFFFFFFF);
190 code++;
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);
198 // Save lmf_addr
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)));
207 // Set new 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 */
231 if (has_caller)
232 alpha_mov1(code, alpha_ra, alpha_a1);
233 else
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;
249 else
250 tramp = (unsigned int*)mono_magic_trampoline;
252 // Restore AT
253 alpha_ldq(code, alpha_at, alpha_sp, (saved_regs_offset + (alpha_at*8)));
255 off = (char *)code - (char *)buf;
256 off += 2*4;
258 if (off % 8)
260 alpha_nop(code);
261 off += 4;
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);
269 code++;
270 *code = (unsigned int)((((unsigned long)tramp) >> 32) & 0xFFFFFFFF);
271 code++;
273 alpha_jsr(code, alpha_ra, alpha_pv, 0);
275 alpha_stq(code, alpha_r0, alpha_sp, framesize);
277 /* Restore LMF */
278 if (1)
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);
288 offset = 16;
290 // Restore all integer regs
291 for (i=0; i<30 /*alpha_pc*/; i++)
293 alpha_ldq(code, i, alpha_sp, offset);
294 offset += 8;
297 // Restore all float regs
298 for (i=0; i<alpha_fzero; i++)
300 alpha_ldt(code, i, alpha_sp, offset);
301 offset += 8;
304 alpha_ldq(code, alpha_r0, alpha_sp, framesize);
306 // Restore stack
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);
311 else
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 /*------------------------------------------------------------------*/
330 /* */
331 /* Name - mono_arch_create_jit_trampoline */
332 /* */
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). */
338 /* */
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. */
344 /* */
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. */
350 /* */
351 /* Parameter - method - Pointer to the method information */
352 /* */
353 /* Returns - A pointer to the newly created code */
354 /* */
355 /*------------------------------------------------------------------*/
357 gpointer
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");
364 return 0;
367 /*========================= End of Function ========================*/
369 /*------------------------------------------------------------------*/
370 /* */
371 /* Name - mono_arch_create_jump_trampoline */
372 /* */
373 /* Function - Create the designated type of trampoline according*/
374 /* to the 'tramp_type' parameter. */
375 /* */
376 /*------------------------------------------------------------------*/
378 MonoJitInfo *
379 mono_arch_create_jump_trampoline (MonoMethod *method)
381 ALPHA_DEBUG("mono_arch_create_jump_trampoline");
383 NOT_IMPLEMENTED;
385 return 0;
388 /*========================= End of Function ========================*/
390 /*------------------------------------------------------------------*/
391 /* */
392 /* Name - mono_arch_create_specific_trampoline */
393 /* */
394 /* Function - ???Create the designated type of trampoline according*/
395 /* to the 'tramp_type' parameter. */
396 /* */
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!!!
401 For Alpha:
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
406 in ra
408 /*------------------------------------------------------------------*/
410 #define TRAMPOLINE_SIZE 64
412 gpointer
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;
437 offset += 2*4;
438 if (offset % 8)
440 alpha_nop(code);
441 offset += 4;
444 alpha_ldq(code, alpha_at, alpha_pv, offset);
445 alpha_br(code, alpha_zero, 2);
447 *code = (unsigned int)(((unsigned long)arg1) & 0xFFFFFFFF);
448 code++;
449 *code = (unsigned int)((((unsigned long)arg1) >> 32) & 0xFFFFFFFF);
450 code++;
452 // Store arg1 on stack
453 alpha_stq(code, alpha_at, alpha_sp, 0);
455 offset = (char *)code - (char *)buf;
456 offset += 2*4;
457 if (offset % 8)
459 alpha_nop(code);
460 offset += 4;
463 alpha_ldq(code, alpha_at, alpha_pv, offset);
464 alpha_br(code, alpha_zero, 2);
466 *code = (unsigned int)(((unsigned long)tramp) & 0xFFFFFFFF);
467 code++;
468 *code = (unsigned int)((((unsigned long)tramp) >> 32) & 0xFFFFFFFF);
469 code++;
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
477 * mcs bootstrap.
479 real_code = mono_domain_code_reserve (domain, TRAMPOLINE_SIZE);
480 size = (char *)code - (char *)buf;
482 memcpy (real_code, buf, size);
484 ALPHA_PRINT
485 g_debug("mono_arch_create_specific_trampoline: Target: %p, Arg1: %p",
486 real_code, arg1);
488 mono_jit_stats.method_trampolines++;
490 if (code_len)
491 *code_len = size;
493 mono_arch_flush_icache ((guchar *)real_code, size);
495 return real_code;
497 /*========================= End of Function ========================*/
499 void
500 mono_arch_nullify_class_init_trampoline (guint8 *code, mgreg_t *regs)
502 unsigned int *pcode = (unsigned int *)code;
504 ALPHA_DEBUG("mono_arch_nullify_class_init_trampoline");
506 // pcode[-2] ldq t12,n(gp)
507 // pcode[-1] jsr ra,(t12),0x20003efcb40
508 if ((pcode[-2] & 0xFFFF0000) == 0xa77d0000 &&
509 pcode[-1] == 0x6b5b4000)
511 // Put "unop" into call inst
512 pcode--;
513 alpha_nop(pcode);
514 alpha_nop(pcode);
515 alpha_nop(pcode);
517 mono_arch_flush_icache ((code-4), 3*4);
519 else
520 g_assert_not_reached ();
523 void
524 mono_arch_patch_callsite (guint8 *method_start, guint8 *code, guint8 *addr)
526 unsigned long *p = (unsigned int *)(code-12);
528 unsigned int *pcode = (unsigned int *)code;
529 unsigned long gp = (unsigned long)pcode;
530 unsigned int call_addr_inst;
531 short high_offset, low_offset;
533 ALPHA_DEBUG("mono_arch_patch_callsite");
535 // Code points to the next instruction after the "jsr"
536 // In current implementation where we put jump addresses
537 // inside the code - we need to put "new" address into
538 // "code-12"
540 // With new method of using GOT we need to find address
541 // where function address is stored
542 // code points to two insts:
543 // ldah gp, high_offset(ra)
544 // lda gp, low_offset(gp)
547 high_offset = *((short *)pcode);
548 low_offset = *((short *)(pcode + 1));
550 gp += 65536 * high_offset + low_offset;
552 call_addr_inst = *(pcode - 2);
554 // Check for load address instruction
555 // It should be ldq t12, offset(gp)
556 if ((call_addr_inst & 0xFFFF0000) == 0xA77D0000)
558 gp += *((short *)(pcode - 2));
560 p = (unsigned long *)gp;
562 ALPHA_PRINT g_debug("Patch callsite at %p to %p\n", p, addr);
564 // TODO - need to to interlocked update here
565 *p = (unsigned long)addr;
570 * mono_arch_get_unbox_trampoline:
571 * @gsctx: the generic sharing context
572 * @m: method pointer
573 * @addr: pointer to native code for @m
575 * when value type methods are called through the vtable we need to unbox the
576 * this argument. This method returns a pointer to a trampoline which does
577 * unboxing before calling the method
579 gpointer
580 mono_arch_get_unbox_trampoline (MonoGenericSharingContext *gsctx, MonoMethod *m, gpointer addr)
582 unsigned int *code, *start_code;
583 int this_reg = 16; //R16
584 int off;
585 MonoDomain *domain = mono_domain_get ();
587 ALPHA_DEBUG("mono_arch_get_unbox_trampoline");
589 if (MONO_TYPE_ISSTRUCT (mono_method_signature (m)->ret))
590 this_reg = 17; //R17
592 start_code = code = (unsigned int *)mono_domain_code_reserve (domain, 32);
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);
599 code++;
600 *code = (unsigned int)((((unsigned long)addr) >> 32) & 0xFFFFFFFF);
601 code++;
603 // Load "addr" into PV (R12)
604 alpha_ldq(code, alpha_pv, alpha_pv, 0);
606 // Jump to addr
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);
613 return start_code;
616 void
617 mono_arch_nullify_plt_entry (guint8 *code, mgreg_t *regs)
619 g_assert_not_reached ();
622 void
623 mono_arch_patch_plt_entry (guint8 *code, gpointer *got, mgreg_t *regs, guint8 *addr)
625 g_assert_not_reached ();
628 gpointer
629 mono_arch_create_rgctx_lazy_fetch_trampoline (guint32 encoded_offset)
631 /* FIXME: implement! */
632 g_assert_not_reached ();
633 return NULL;