/*------------------------------------------------------------------*/ /* */ /* Name - tramp-alpha.c */ /* */ /* Function - JIT trampoline code for Alpha. */ /* */ /* Name - Sergey Tikhonov (tsv@solvo.ru) */ /* */ /* Date - January, 2006 */ /* */ /* Derivation - From exceptions-amd64 & exceptions-ia64 */ /* Dietmar Maurer (dietmar@ximian.com) */ /* Zoltan Varga (vargaz@gmail.com) */ /* */ /* */ /*------------------------------------------------------------------*/ /*------------------------------------------------------------------*/ /* D e f i n e s */ /*------------------------------------------------------------------*/ #define ALPHA_DEBUG(x) \ if (mini_alpha_verbose_level) \ g_debug ("ALPHA_DEBUG: %s is called.", x); #define ALPHA_PRINT if (mini_alpha_verbose_level) /*========================= End of Defines =========================*/ /*------------------------------------------------------------------*/ /* I n c l u d e s */ /*------------------------------------------------------------------*/ #include #include #include #include #include #include #include #include #include "mini.h" #include "mini-alpha.h" /*========================= End of Includes ========================*/ /*------------------------------------------------------------------*/ /* T y p e d e f s */ /*------------------------------------------------------------------*/ /*========================= End of Typedefs ========================*/ /*------------------------------------------------------------------*/ /* P r o t o t y p e s */ /*------------------------------------------------------------------*/ /*========================= End of Prototypes ======================*/ /*------------------------------------------------------------------*/ /* G l o b a l V a r i a b l e s */ /*------------------------------------------------------------------*/ /*====================== End of Global Variables ===================*/ extern int mini_alpha_verbose_level; /*------------------------------------------------------------------*/ /* */ /* Name - mono_arch_create_trampoline_code */ /* */ /* Function - Create the designated type of trampoline according*/ /* to the 'tramp_type' parameter. */ /* */ /* This code should expect to be called by tramp stub function On Alpha: - pv points to start of stub function - at points to start of this trampoline - allocate stack to save all regs and lmfs - save regs - save lmf - fill params for trampoline methods (They expect 4 params) - call trampoline method (by standard call convention (pv + ra)) - save return value (r0) - restore saved regs + lmfs - restore stack (don't forget space allocated by stub) - use saved return values as new address to give control to - return or jump to new address (don't expect to return here - don't save return address. RA will be holding return address of original caller of tramp stub function). New address function expect standart calling convention (pv) */ /*------------------------------------------------------------------*/ guchar * mono_arch_create_trampoline_code (MonoTrampolineType tramp_type) { unsigned int *buf, *code, *tramp; int i, offset, framesize, off, lmf_offset, saved_regs_offset; //int saved_fpregs_offset, saved_regs_offset, method_offset, tramp_offset; gboolean has_caller; ALPHA_DEBUG("mono_arch_create_trampoline_code"); if (tramp_type == MONO_TRAMPOLINE_JUMP) has_caller = FALSE; else has_caller = TRUE; code = buf = mono_global_codeman_reserve (1024); framesize = 1024 + sizeof (MonoLMF); framesize = (framesize + (MONO_ARCH_FRAME_ALIGNMENT - 1)) & ~(MONO_ARCH_FRAME_ALIGNMENT - 1); offset = 16; // Expect that generated code is called with 2 parameters // method and tramp (in a0 and a1) // Allocate stack alpha_lda(code, alpha_sp, alpha_sp, -framesize); /* store call convention parameters on stack.*/ alpha_stq( code, alpha_ra, alpha_sp, 0 ); // ra alpha_stq( code, alpha_fp, alpha_sp, 8 ); // fp saved_regs_offset = offset; // Store all integer regs for (i=0; i<30 /*alpha_pc*/; i++) { alpha_stq(code, i, alpha_sp, offset); offset += 8; } // Store all fp regs for (i=0; i> 32) & 0xFFFFFFFF); code++; /* * The call might clobber argument registers, but they are already * saved to the stack/global regs. */ alpha_jsr(code, alpha_ra, alpha_pv, 0); // Save lmf_addr alpha_stq(code, alpha_r0, alpha_sp, (lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr))); // Load "previous_lmf" member of MonoLMF struct alpha_ldq(code, alpha_r1, alpha_r0, 0); // Save it to MonoLMF struct alpha_stq(code, alpha_r1, alpha_sp, (lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf))); // Set new LMF alpha_lda(code, alpha_r1, alpha_sp, lmf_offset); alpha_stq(code, alpha_r1, alpha_r0, 0); } /* set the frame pointer */ alpha_mov1( code, alpha_sp, alpha_fp ); /* Arg3 is the method/vtable ptr */ alpha_ldq(code, alpha_a2, alpha_sp, framesize); //alpha_mov1(code, alpha_a0, alpha_a2); /* Arg4 is the trampoline address */ // Load PV from saved regs - later optimize it and load into a3 directly alpha_ldq(code, alpha_pv, alpha_sp, (saved_regs_offset + (alpha_pv*8))); alpha_mov1(code, alpha_pv, alpha_a3); //alpha_mov1(code, alpha_a1, alpha_a3); /* Arg1 is the pointer to the saved registers */ alpha_lda(code, alpha_a0, alpha_sp, 16); alpha_ldq(code, alpha_ra, alpha_sp, (saved_regs_offset + (alpha_ra*8))); /* Arg2 is the address of the calling code */ if (has_caller) alpha_mov1(code, alpha_ra, alpha_a1); else alpha_mov1(code, alpha_zero, alpha_a1); /* Arg3 is the method/vtable ptr alpha_mov1(code, alpha_a0, alpha_a2); Arg4 is the trampoline address alpha_mov1(code, alpha_a1, alpha_a3); */ if (tramp_type == MONO_TRAMPOLINE_CLASS_INIT) tramp = (unsigned int*)mono_class_init_trampoline; else if (tramp_type == MONO_TRAMPOLINE_AOT) tramp = (unsigned int*)mono_aot_trampoline; else if (tramp_type == MONO_TRAMPOLINE_DELEGATE) tramp = (unsigned int*)mono_delegate_trampoline; else tramp = (unsigned int*)mono_magic_trampoline; // Restore AT alpha_ldq(code, alpha_at, alpha_sp, (saved_regs_offset + (alpha_at*8))); off = (char *)code - (char *)buf; off += 2*4; if (off % 8) { alpha_nop(code); off += 4; } // alpha_at points to start of this method !!! alpha_ldq(code, alpha_pv, alpha_at, off); alpha_br(code, alpha_zero, 2); *code = (unsigned int)(((unsigned long)tramp) & 0xFFFFFFFF); code++; *code = (unsigned int)((((unsigned long)tramp) >> 32) & 0xFFFFFFFF); code++; alpha_jsr(code, alpha_ra, alpha_pv, 0); alpha_stq(code, alpha_r0, alpha_sp, framesize); /* Restore LMF */ if (1) { /* Restore previous lmf */ alpha_ldq(code, alpha_at, alpha_sp, (lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf))); alpha_ldq(code, alpha_ra, alpha_sp, (lmf_offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr))); alpha_stq(code, alpha_at, alpha_ra, 0); } offset = 16; // Restore all integer regs for (i=0; i<30 /*alpha_pc*/; i++) { alpha_ldq(code, i, alpha_sp, offset); offset += 8; } // Restore all float regs for (i=0; i> 32) & 0xFFFFFFFF); code++; // Store arg1 on stack alpha_stq(code, alpha_at, alpha_sp, 0); offset = (char *)code - (char *)buf; offset += 2*4; if (offset % 8) { alpha_nop(code); offset += 4; } alpha_ldq(code, alpha_at, alpha_pv, offset); alpha_br(code, alpha_zero, 2); *code = (unsigned int)(((unsigned long)tramp) & 0xFFFFFFFF); code++; *code = (unsigned int)((((unsigned long)tramp) >> 32) & 0xFFFFFFFF); code++; // Jump to trampoline alpha_jmp(code, alpha_zero, alpha_at, 0); g_assert (((char *)code - (char *)buf) <= TRAMPOLINE_SIZE); /* * FIXME: Changing the size to code - buf causes strange crashes during * mcs bootstrap. */ real_code = mono_domain_code_reserve (domain, TRAMPOLINE_SIZE); size = (char *)code - (char *)buf; memcpy (real_code, buf, size); ALPHA_PRINT g_debug("mono_arch_create_specific_trampoline: Target: %p, Arg1: %p", real_code, arg1); mono_jit_stats.method_trampolines++; if (code_len) *code_len = size; mono_arch_flush_icache ((guchar *)real_code, size); return real_code; } /*========================= End of Function ========================*/ void mono_arch_nullify_class_init_trampoline (guint8 *code, mgreg_t *regs) { unsigned int *pcode = (unsigned int *)code; ALPHA_DEBUG("mono_arch_nullify_class_init_trampoline"); // pcode[-2] ldq t12,n(gp) // pcode[-1] jsr ra,(t12),0x20003efcb40 if ((pcode[-2] & 0xFFFF0000) == 0xa77d0000 && pcode[-1] == 0x6b5b4000) { // Put "unop" into call inst pcode--; alpha_nop(pcode); alpha_nop(pcode); alpha_nop(pcode); mono_arch_flush_icache ((code-4), 3*4); } else g_assert_not_reached (); } void mono_arch_patch_callsite (guint8 *method_start, guint8 *code, guint8 *addr) { unsigned long *p = (unsigned int *)(code-12); unsigned int *pcode = (unsigned int *)code; unsigned long gp = (unsigned long)pcode; unsigned int call_addr_inst; short high_offset, low_offset; ALPHA_DEBUG("mono_arch_patch_callsite"); // Code points to the next instruction after the "jsr" // In current implementation where we put jump addresses // inside the code - we need to put "new" address into // "code-12" // With new method of using GOT we need to find address // where function address is stored // code points to two insts: // ldah gp, high_offset(ra) // lda gp, low_offset(gp) // high_offset = *((short *)pcode); low_offset = *((short *)(pcode + 1)); gp += 65536 * high_offset + low_offset; call_addr_inst = *(pcode - 2); // Check for load address instruction // It should be ldq t12, offset(gp) if ((call_addr_inst & 0xFFFF0000) == 0xA77D0000) { gp += *((short *)(pcode - 2)); p = (unsigned long *)gp; ALPHA_PRINT g_debug("Patch callsite at %p to %p\n", p, addr); // TODO - need to to interlocked update here *p = (unsigned long)addr; } } /* * mono_arch_get_unbox_trampoline: * @gsctx: the generic sharing context * @m: method pointer * @addr: pointer to native code for @m * * when value type methods are called through the vtable we need to unbox the * this argument. This method returns a pointer to a trampoline which does * unboxing before calling the method */ gpointer mono_arch_get_unbox_trampoline (MonoGenericSharingContext *gsctx, MonoMethod *m, gpointer addr) { unsigned int *code, *start_code; int this_reg = 16; //R16 int off; MonoDomain *domain = mono_domain_get (); ALPHA_DEBUG("mono_arch_get_unbox_trampoline"); if (MONO_TYPE_ISSTRUCT (mono_method_signature (m)->ret)) this_reg = 17; //R17 start_code = code = (unsigned int *)mono_domain_code_reserve (domain, 32); // Adjust this by size of MonoObject alpha_addq_(code, this_reg, sizeof(MonoObject), this_reg); // 0 alpha_bsr(code, alpha_pv, 2); // 4 *code = (unsigned int)(((unsigned long)addr) & 0xFFFFFFFF); code++; *code = (unsigned int)((((unsigned long)addr) >> 32) & 0xFFFFFFFF); code++; // Load "addr" into PV (R12) alpha_ldq(code, alpha_pv, alpha_pv, 0); // Jump to addr alpha_jsr(code, alpha_zero, alpha_pv, 0); g_assert (((char *)code - (char *)start_code) < 32); mono_arch_flush_icache (start_code, (char *)code - (char *)start_code); return start_code; } void mono_arch_nullify_plt_entry (guint8 *code, mgreg_t *regs) { g_assert_not_reached (); } void mono_arch_patch_plt_entry (guint8 *code, gpointer *got, mgreg_t *regs, guint8 *addr) { g_assert_not_reached (); } gpointer mono_arch_create_rgctx_lazy_fetch_trampoline (guint32 encoded_offset) { /* FIXME: implement! */ g_assert_not_reached (); return NULL; }