update rx (mobile builds).
[mono-project.git] / mono / mini / tramp-alpha.c
blobcab03d65ec5f8a8af8a17cf9e0edfff7e320d826
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 if (code_len)
489 *code_len = size;
491 mono_arch_flush_icache ((guchar *)real_code, size);
493 return real_code;
495 /*========================= End of Function ========================*/
497 void
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
510 pcode--;
511 alpha_nop(pcode);
512 alpha_nop(pcode);
513 alpha_nop(pcode);
515 mono_arch_flush_icache ((code-4), 3*4);
517 else
518 g_assert_not_reached ();
521 void
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
536 // "code-12"
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
570 * @m: method pointer
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
577 gpointer
578 mono_arch_get_unbox_trampoline (MonoGenericSharingContext *gsctx, MonoMethod *m, gpointer addr)
580 unsigned int *code, *start_code;
581 int this_reg = 16; //R16
582 int off;
583 MonoDomain *domain = mono_domain_get ();
585 ALPHA_DEBUG("mono_arch_get_unbox_trampoline");
587 if (MONO_TYPE_ISSTRUCT (mono_method_signature (m)->ret))
588 this_reg = 17; //R17
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);
597 code++;
598 *code = (unsigned int)((((unsigned long)addr) >> 32) & 0xFFFFFFFF);
599 code++;
601 // Load "addr" into PV (R12)
602 alpha_ldq(code, alpha_pv, alpha_pv, 0);
604 // Jump to addr
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);
611 return start_code;
614 void
615 mono_arch_nullify_plt_entry (guint8 *code, mgreg_t *regs)
617 g_assert_not_reached ();
620 void
621 mono_arch_patch_plt_entry (guint8 *code, gpointer *got, mgreg_t *regs, guint8 *addr)
623 g_assert_not_reached ();
626 gpointer
627 mono_arch_create_rgctx_lazy_fetch_trampoline (guint32 encoded_offset)
629 /* FIXME: implement! */
630 g_assert_not_reached ();
631 return NULL;