gpointer mono_arch_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_type, MonoDomain *domain, guint32 *code_len) { guint8 *code, *buf, *tramp; gint32 displace; tramp = mono_get_trampoline_code (tramp_type); /*----------------------------------------------------------*/ /* This is the method-specific part of the trampoline. Its */ /* purpose is to provide the generic part with the */ /* MonoMethod *method pointer. We'll use r1 to keep it. */ /*----------------------------------------------------------*/ code = buf = mono_domain_code_reserve (domain, SPECIFIC_TRAMPOLINE_SIZE); s390_basr (buf, s390_r1, 0); s390_j (buf, 6); s390_llong(buf, arg1); s390_lg (buf, s390_r1, 0, s390_r1, 4); displace = (tramp - buf) / 2; s390_jcl (buf, S390_CC_UN, displace); /* Flush instruction cache, since we've generated code */ mono_arch_flush_icache (code, buf - code); /* Sanity check */ g_assert ((buf - code) <= SPECIFIC_TRAMPOLINE_SIZE); if (code_len) *code_len = buf - code; return code; }
gpointer mono_arch_get_unbox_trampoline (MonoGenericSharingContext *gsctx, MonoMethod *method, gpointer addr) { guint8 *code, *start; int this_pos = s390_r2; MonoDomain *domain = mono_domain_get (); start = addr; if (MONO_TYPE_ISSTRUCT (mono_method_signature (method)->ret)) this_pos = s390_r3; start = code = mono_domain_code_reserve (domain, 28); s390_basr (code, s390_r13, 0); s390_j (code, 4); s390_word (code, addr); s390_l (code, s390_r1, 0, s390_r13, 4); s390_ahi (code, this_pos, sizeof(MonoObject)); s390_br (code, s390_r1); g_assert ((code - start) <= 28); mono_arch_flush_icache (start, code - start); return start; }
gpointer mono_arch_get_static_rgctx_trampoline (MonoMethod *m, MonoMethodRuntimeGenericContext *mrgctx, gpointer addr) { guint8 *code, *start; gint32 displace; int buf_len; MonoDomain *domain = mono_domain_get (); buf_len = 32; start = code = mono_domain_code_reserve (domain, buf_len); s390_basr (code, s390_r1, 0); s390_j (code, 6); s390_llong(code, mrgctx); s390_lg (code, MONO_ARCH_RGCTX_REG, 0, s390_r1, 4); displace = ((uintptr_t) addr - (uintptr_t) code) / 2; s390_jg (code, displace); g_assert ((code - start) < buf_len); mono_arch_flush_icache (start, code - start); return(start); }
gpointer mono_arch_get_unbox_trampoline (MonoMethod *method, gpointer addr) { guint8 *code, *start; int this_pos = s390_r2; MonoDomain *domain = mono_domain_get (); start = code = mono_domain_code_reserve (domain, 28); s390_basr (code, s390_r1, 0); s390_j (code, 6); s390_llong(code, addr); s390_lg (code, s390_r1, 0, s390_r1, 4); s390_aghi (code, this_pos, sizeof(MonoObject)); s390_br (code, s390_r1); g_assert ((code - start) <= 28); mono_arch_flush_icache (start, code - start); return start; }
guchar* mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInfo **info, gboolean aot) { guint8 *buf, *tramp, *code; int i, offset, lmfOffset; g_assert (!aot); if (info) *info = NULL; /* Now we'll create in 'buf' the S/390 trampoline code. This is the trampoline code common to all methods */ code = buf = mono_global_codeman_reserve(512); /*----------------------------------------------------------- STEP 0: First create a non-standard function prologue with a stack size big enough to save our registers. -----------------------------------------------------------*/ s390_stmg (buf, s390_r6, s390_r15, STK_BASE, S390_REG_SAVE_OFFSET); s390_lgr (buf, s390_r11, s390_r15); s390_aghi (buf, STK_BASE, -CREATE_STACK_SIZE); s390_stg (buf, s390_r11, 0, STK_BASE, 0); s390_stg (buf, s390_r1, 0, STK_BASE, METHOD_SAVE_OFFSET); s390_stmg (buf, s390_r2, s390_r5, STK_BASE, CREATE_GR_OFFSET); /* Save the FP registers */ offset = CREATE_FP_OFFSET; for (i = s390_f0; i <= s390_f15; ++i) { s390_std (buf, i, 0, STK_BASE, offset); offset += 8; } /*---------------------------------------------------------- STEP 1: call 'mono_get_lmf_addr()' to get the address of our LMF. We'll need to restore it after the call to 's390_magic_trampoline' and before the call to the native method. ----------------------------------------------------------*/ s390_basr (buf, s390_r13, 0); s390_j (buf, 6); s390_llong(buf, mono_get_lmf_addr); s390_lg (buf, s390_r1, 0, s390_r13, 4); s390_basr (buf, s390_r14, s390_r1); /*---------------------------------------------------------------*/ /* we build the MonoLMF structure on the stack - see mini-s390.h */ /* Keep in sync with the code in mono_arch_emit_prolog */ /*---------------------------------------------------------------*/ lmfOffset = CREATE_STACK_SIZE - sizeof(MonoLMF); s390_lgr (buf, s390_r13, STK_BASE); s390_aghi (buf, s390_r13, lmfOffset); /*---------------------------------------------------------------*/ /* Set lmf.lmf_addr = jit_tls->lmf */ /*---------------------------------------------------------------*/ s390_stg (buf, s390_r2, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, lmf_addr)); /*---------------------------------------------------------------*/ /* Get current lmf */ /*---------------------------------------------------------------*/ s390_lg (buf, s390_r0, 0, s390_r2, 0); /*---------------------------------------------------------------*/ /* Set our lmf as the current lmf */ /*---------------------------------------------------------------*/ s390_stg (buf, s390_r13, 0, s390_r2, 0); /*---------------------------------------------------------------*/ /* Have our lmf.previous_lmf point to the last lmf */ /*---------------------------------------------------------------*/ s390_stg (buf, s390_r0, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, previous_lmf)); /*---------------------------------------------------------------*/ /* save method info */ /*---------------------------------------------------------------*/ s390_lg (buf, s390_r1, 0, STK_BASE, METHOD_SAVE_OFFSET); s390_stg (buf, s390_r1, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, method)); /*---------------------------------------------------------------*/ /* save the current SP */ /*---------------------------------------------------------------*/ s390_lg (buf, s390_r1, 0, STK_BASE, 0); s390_stg (buf, s390_r1, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, ebp)); /*---------------------------------------------------------------*/ /* save the current IP */ /*---------------------------------------------------------------*/ if (tramp_type == MONO_TRAMPOLINE_JUMP) { s390_lghi (buf, s390_r1, 0); } else { s390_lg (buf, s390_r1, 0, s390_r1, S390_RET_ADDR_OFFSET); // s390_la (buf, s390_r1, 0, s390_r1, 0); } s390_stg (buf, s390_r1, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, eip)); /*---------------------------------------------------------------*/ /* Save general and floating point registers */ /*---------------------------------------------------------------*/ s390_mvc (buf, 4*sizeof(gulong), s390_r13, G_STRUCT_OFFSET(MonoLMF, gregs[2]), STK_BASE, CREATE_GR_OFFSET); s390_mvc (buf, 10*sizeof(gulong), s390_r13, G_STRUCT_OFFSET(MonoLMF, gregs[6]), s390_r11, S390_REG_SAVE_OFFSET); /* Simply copy fpregs already saved above */ s390_mvc (buf, 16*sizeof(double), s390_r13, G_STRUCT_OFFSET(MonoLMF, fregs[0]), STK_BASE, CREATE_FP_OFFSET); /*---------------------------------------------------------------*/ /* STEP 2: call the C trampoline function */ /*---------------------------------------------------------------*/ /* Set arguments */ /* Arg 1: mgreg_t *regs. We pass sp instead */ s390_la (buf, s390_r2, 0, STK_BASE, CREATE_STACK_SIZE); /* Arg 2: code (next address to the instruction that called us) */ if (tramp_type == MONO_TRAMPOLINE_JUMP) { s390_lghi (buf, s390_r3, 0); } else { s390_lg (buf, s390_r3, 0, s390_r11, S390_RET_ADDR_OFFSET); } /* Arg 3: MonoMethod *method. It was put in r1 by the method-specific trampoline code, and then saved before the call to mono_get_lmf_addr()'. */ s390_lg (buf, s390_r4, 0, STK_BASE, METHOD_SAVE_OFFSET); /* Arg 4: trampoline address. Ignore for now */ /* Calculate call address and call the C trampoline. Return value will be in r2 */ s390_basr (buf, s390_r13, 0); s390_j (buf, 6); tramp = (guint8*)mono_get_trampoline_func (tramp_type); s390_llong (buf, tramp); s390_lg (buf, s390_r1, 0, s390_r13, 4); s390_basr (buf, s390_r14, s390_r1); /* OK, code address is now on r2. Move it to r1, so that we can restore r2 and use it from r1 later */ s390_lgr (buf, s390_r1, s390_r2); /*---------------------------------------------------------- STEP 3: Restore the LMF ----------------------------------------------------------*/ restoreLMF(buf, STK_BASE, CREATE_STACK_SIZE); /*---------------------------------------------------------- STEP 4: call the compiled method ----------------------------------------------------------*/ /* Restore registers */ s390_lmg (buf, s390_r2, s390_r5, STK_BASE, CREATE_GR_OFFSET); /* Restore the FP registers */ offset = CREATE_FP_OFFSET; for (i = s390_f0; i <= s390_f15; ++i) { s390_ld (buf, i, 0, STK_BASE, offset); offset += 8; } /* Restore stack pointer and jump to the code - R14 contains the return address to our caller */ s390_lgr (buf, STK_BASE, s390_r11); s390_lmg (buf, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET); if (tramp_type == MONO_TRAMPOLINE_CLASS_INIT || tramp_type == MONO_TRAMPOLINE_GENERIC_CLASS_INIT) s390_br (buf, s390_r14); else s390_br (buf, s390_r1); /* Flush instruction cache, since we've generated code */ mono_arch_flush_icache (code, buf - code); /* Sanity check */ g_assert ((buf - code) <= 512); return code; }