void mono_arch_patch_callsite (guint8 *method_start, guint8 *orig_code, guint8 *addr) { gint32 displace; unsigned short opcode; opcode = *((unsigned short *) (orig_code - 6)); if (opcode == 0xc0e5) { /* This is the 'brasl' instruction */ orig_code -= 4; displace = ((gssize) addr - (gssize) (orig_code - 2)) / 2; s390_patch_rel (orig_code, displace); mono_arch_flush_icache (orig_code, 4); } else { /* This should be a 'lg %r14,4(%r13)' then a 'basr r14, r14' instruction */ g_assert (orig_code [-8] == 0xe3); g_assert (orig_code [-7] == 0xe0); g_assert (orig_code [-6] == 0xd0); g_assert (orig_code [-5] == 0x04); g_assert (orig_code [-4] == 0x00); g_assert (orig_code [-3] == 0x04); opcode = *((unsigned short*) (orig_code - 2)); g_assert (opcode == 0x0dee); /* The call address is stored in the 8 bytes preceeding the basr instruction */ s390_patch_addr(orig_code - 16, (gssize)addr); mono_arch_flush_icache (orig_code - 16, 8); } }
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_SET (code, MONO_ARCH_RGCTX_REG, mrgctx); 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); mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_HELPER, NULL); return(start); }
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; }
/* * mono_arch_get_restore_context: * * Returns a pointer to a method which restores a previously saved sigcontext. */ gpointer mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot) { static guint32 *start; static int inited = 0; guint32 *code; g_assert (!aot); if (info) *info = NULL; if (inited) return start; code = start = mono_global_codeman_reserve (32 * sizeof (guint32)); sparc_ldi_imm (code, sparc_o0, G_STRUCT_OFFSET (MonoContext, ip), sparc_i7); sparc_ldi_imm (code, sparc_o0, G_STRUCT_OFFSET (MonoContext, sp), sparc_i6); sparc_jmpl_imm (code, sparc_i7, 0, sparc_g0); /* FIXME: This does not return to the correct window */ sparc_restore_imm (code, sparc_g0, 0, sparc_g0); g_assert ((code - start) < 32); mono_arch_flush_icache ((guint8*)start, (guint8*)code - (guint8*)start); inited = 1; return start; }
/* * mono_arch_get_unbox_trampoline: * @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 (MonoMethod *m, gpointer addr) { guint8 *code, *start; int reg; start = code = mono_global_codeman_reserve (36); /* This executes in the context of the caller, hence o0 */ sparc_add_imm (code, 0, sparc_o0, sizeof (MonoObject), sparc_o0); #ifdef SPARCV9 reg = sparc_g4; #else reg = sparc_g1; #endif sparc_set (code, addr, reg); sparc_jmpl (code, reg, sparc_g0, sparc_g0); sparc_nop (code); g_assert ((code - start) <= 36); mono_arch_flush_icache (start, code - start); mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), NULL); 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 (); char trampName[128]; start = code = mono_domain_code_reserve (domain, 28); S390_SET (code, s390_r1, addr); s390_aghi (code, this_pos, MONO_ABI_SIZEOF (MonoObject)); s390_br (code, s390_r1); g_assert ((code - start) <= 28); mono_arch_flush_icache (start, code - start); MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_UNBOX_TRAMPOLINE, method)); snprintf(trampName, sizeof(trampName), "%s_unbox_trampoline", method->name); mono_tramp_info_register (mono_tramp_info_create (trampName, start, code - start, NULL, NULL), domain); return start; }
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_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_SET (buf, s390_r1, arg1); displace = (tramp - buf) / 2; s390_jg (buf, displace); /* Flush instruction cache, since we've generated code */ mono_arch_flush_icache (code, buf - code); MONO_PROFILER_RAISE (jit_code_buffer, (buf, code - buf, MONO_PROFILER_CODE_BUFFER_SPECIFIC_TRAMPOLINE, (void *) mono_get_generic_trampoline_simple_name (tramp_type))); /* Sanity check */ g_assert ((buf - code) <= SPECIFIC_TRAMPOLINE_SIZE); if (code_len) *code_len = buf - code; return code; }
gpointer mono_arch_get_static_rgctx_trampoline (gpointer arg, 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_SET (code, MONO_ARCH_RGCTX_REG, arg); 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); MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL)); mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), domain); return(start); }
/* * mono_arch_get_call_filter: * * Returns a pointer to a method which calls an exception filter. We * also use this function to call finally handlers (we pass NULL as * @exc object in this case). */ gpointer mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot) { guint8 *start, *code; int alloc_size, pos, i; int size = MONO_PPC_32_64_CASE (320, 500) + PPC_FTNPTR_SIZE; MonoJumpInfo *ji = NULL; GSList *unwind_ops = NULL; /* call_filter (MonoContext *ctx, unsigned long eip, gpointer exc) */ code = start = mono_global_codeman_reserve (size); if (!aot) code = mono_ppc_create_pre_code_ftnptr (code); /* store ret addr */ ppc_mflr (code, ppc_r0); ppc_stptr (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp); alloc_size = REG_SAVE_STACK_FRAME_SIZE; /* allocate stack frame and set link from sp in ctx */ g_assert ((alloc_size & (MONO_ARCH_FRAME_ALIGNMENT-1)) == 0); ppc_ldptr (code, ppc_r0, G_STRUCT_OFFSET (MonoContext, sc_sp), ppc_r3); ppc_ldptr_indexed (code, ppc_r0, ppc_r0, ppc_r0); ppc_stptr_update (code, ppc_r0, -alloc_size, ppc_sp); code = emit_save_saved_regs (code, alloc_size); /* restore all the regs from ctx (in r3), but not r1, the stack pointer */ restore_regs_from_context (ppc_r3, ppc_r6, ppc_r7); /* call handler at eip (r4) and set the first arg with the exception (r5) */ ppc_mtctr (code, ppc_r4); ppc_mr (code, ppc_r3, ppc_r5); ppc_bcctrl (code, PPC_BR_ALWAYS, 0); /* epilog */ ppc_ldptr (code, ppc_r0, alloc_size + PPC_RET_ADDR_OFFSET, ppc_sp); ppc_mtlr (code, ppc_r0); /* restore all the regs from the stack */ pos = alloc_size; for (i = 31; i >= 14; --i) { pos -= sizeof (gdouble); ppc_lfd (code, i, pos, ppc_sp); } pos -= sizeof (gpointer) * MONO_SAVED_GREGS; ppc_load_multiple_regs (code, ppc_r13, pos, ppc_sp); ppc_addic (code, ppc_sp, ppc_sp, alloc_size); ppc_blr (code); g_assert ((code - start) < size); mono_arch_flush_icache (start, code - start); mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL); if (info) *info = mono_tramp_info_create ("call_filter", start, code - start, ji, unwind_ops); 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_static_rgctx_trampoline (gpointer arg, gpointer addr) { guint8 *code, *start; int buf_len; GSList *unwind_ops; MonoDomain *domain = mono_domain_get (); buf_len = 10; start = code = mono_domain_code_reserve (domain, buf_len); unwind_ops = mono_arch_get_cie_program (); x86_mov_reg_imm (code, MONO_ARCH_RGCTX_REG, arg); x86_jump_code (code, addr); g_assert ((code - start) <= buf_len); mono_arch_flush_icache (start, code - start); MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL)); mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, unwind_ops), domain); return start; }
/* * mono_arch_create_general_rgctx_lazy_fetch_trampoline: * * This is a general variant of the rgctx fetch trampolines. It receives a pointer to gpointer[2] in the rgctx reg. The first entry contains the slot, the second * the trampoline to call if the slot is not filled. */ gpointer mono_arch_create_general_rgctx_lazy_fetch_trampoline (MonoTrampInfo **info, gboolean aot) { guint8 *code, *buf; int tramp_size; MonoJumpInfo *ji = NULL; GSList *unwind_ops = NULL; g_assert (aot); unwind_ops = mono_arch_get_cie_program (); tramp_size = 64; code = buf = mono_global_codeman_reserve (tramp_size); // FIXME: Currently, we always go to the slow path. /* Load trampoline addr */ x86_mov_reg_membase (code, X86_EAX, MONO_ARCH_RGCTX_REG, 4, 4); /* Load mrgctx/vtable */ x86_mov_reg_membase (code, MONO_ARCH_VTABLE_REG, X86_ESP, 4, 4); x86_jump_reg (code, X86_EAX); mono_arch_flush_icache (buf, code - buf); MONO_PROFILER_RAISE (jit_code_buffer, (buf, code - buf, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL)); g_assert (code - buf <= tramp_size); *info = mono_tramp_info_create ("rgctx_fetch_trampoline_general", buf, code - buf, ji, unwind_ops); return buf; }
/* * arch_get_restore_context: * * Returns a pointer to a method which restores a previously saved sigcontext. * The first argument in r3 is the pointer to the context. */ gpointer mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot) { guint8 *start, *code; int size = MONO_PPC_32_64_CASE (128, 172) + PPC_FTNPTR_SIZE; MonoJumpInfo *ji = NULL; GSList *unwind_ops = NULL; code = start = mono_global_codeman_reserve (size); if (!aot) code = mono_ppc_create_pre_code_ftnptr (code); restore_regs_from_context (ppc_r3, ppc_r4, ppc_r5); /* restore also the stack pointer */ ppc_ldptr (code, ppc_sp, G_STRUCT_OFFSET (MonoContext, sc_sp), ppc_r3); //ppc_break (code); /* jump to the saved IP */ ppc_mtctr (code, ppc_r4); ppc_bcctr (code, PPC_BR_ALWAYS, 0); /* never reached */ ppc_break (code); g_assert ((code - start) <= size); mono_arch_flush_icache (start, code - start); MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL)); if (info) *info = mono_tramp_info_create ("restore_context", start, code - start, ji, unwind_ops); return start; }
gpointer mono_arch_get_static_rgctx_trampoline (MonoMethod *m, MonoMethodRuntimeGenericContext *mrgctx, gpointer addr) { guint8 *code, *start; gint32 displace; int buf_len; char trampName[128]; MonoDomain *domain = mono_domain_get (); buf_len = 32; start = code = mono_domain_code_reserve (domain, buf_len); S390_SET (code, MONO_ARCH_RGCTX_REG, mrgctx); 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); if (mono_profiler_events & MONO_PROFILE_JIT_COMPILATION) mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_HELPER, NULL); snprintf(trampName, sizeof(trampName), "%s_rgctx_trampoline", m->name); mono_tramp_info_register (mono_tramp_info_create (trampName, start, code - start, NULL, NULL), domain); return(start); }
gpointer mono_arch_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_type, MonoDomain *domain, guint32 *code_len) { guint32 *code, *buf, *tramp; tramp = mono_get_trampoline_code (tramp_type); code = buf = mono_domain_code_reserve (domain, TRAMPOLINE_SIZE * 4); /* We have to use g5 here because there is no other free register */ sparc_set (code, tramp, sparc_g5); sparc_jmpl (code, sparc_g5, sparc_g0, sparc_g5); sparc_nop (code); #ifdef SPARCV9 g_assert_not_reached (); #else *code = (guint32)arg1; code ++; #endif g_assert ((code - buf) <= TRAMPOLINE_SIZE); if (code_len) *code_len = (code - buf) * 4; mono_arch_flush_icache ((guint8*)buf, (code - buf) * 4); return buf; }
/* * mono_arch_get_restore_context: * * Returns a pointer to a method which restores a previously saved sigcontext. */ gpointer mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot) { guint8 *start = NULL; guint8 *code; MonoJumpInfo *ji = NULL; GSList *unwind_ops = NULL; /* restore_contect (MonoContext *ctx) */ start = code = mono_global_codeman_reserve (256); amd64_mov_reg_reg (code, AMD64_R11, AMD64_ARG_REG1, 8); /* Restore all registers except %rip and %r11 */ amd64_mov_reg_membase (code, AMD64_RAX, AMD64_R11, MONO_STRUCT_OFFSET (MonoContext, rax), 8); amd64_mov_reg_membase (code, AMD64_RCX, AMD64_R11, MONO_STRUCT_OFFSET (MonoContext, rcx), 8); amd64_mov_reg_membase (code, AMD64_RDX, AMD64_R11, MONO_STRUCT_OFFSET (MonoContext, rdx), 8); amd64_mov_reg_membase (code, AMD64_RBX, AMD64_R11, MONO_STRUCT_OFFSET (MonoContext, rbx), 8); amd64_mov_reg_membase (code, AMD64_RBP, AMD64_R11, MONO_STRUCT_OFFSET (MonoContext, rbp), 8); amd64_mov_reg_membase (code, AMD64_RSI, AMD64_R11, MONO_STRUCT_OFFSET (MonoContext, rsi), 8); amd64_mov_reg_membase (code, AMD64_RDI, AMD64_R11, MONO_STRUCT_OFFSET (MonoContext, rdi), 8); //amd64_mov_reg_membase (code, AMD64_R8, AMD64_R11, MONO_STRUCT_OFFSET (MonoContext, r8), 8); //amd64_mov_reg_membase (code, AMD64_R9, AMD64_R11, MONO_STRUCT_OFFSET (MonoContext, r9), 8); //amd64_mov_reg_membase (code, AMD64_R10, AMD64_R11, MONO_STRUCT_OFFSET (MonoContext, r10), 8); amd64_mov_reg_membase (code, AMD64_R12, AMD64_R11, MONO_STRUCT_OFFSET (MonoContext, r12), 8); amd64_mov_reg_membase (code, AMD64_R13, AMD64_R11, MONO_STRUCT_OFFSET (MonoContext, r13), 8); amd64_mov_reg_membase (code, AMD64_R14, AMD64_R11, MONO_STRUCT_OFFSET (MonoContext, r14), 8); #if !defined(__native_client_codegen__) amd64_mov_reg_membase (code, AMD64_R15, AMD64_R11, MONO_STRUCT_OFFSET (MonoContext, r15), 8); #endif /* * The context resides on the stack, in the stack frame of the * caller of this function. The stack pointer that we need to * restore is potentially many stack frames higher up, so the * distance between them can easily be more than the red zone * size. Hence the stack pointer can be restored only after * we have finished loading everything from the context. */ amd64_mov_reg_membase (code, AMD64_R8, AMD64_R11, MONO_STRUCT_OFFSET (MonoContext, rsp), 8); amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11, MONO_STRUCT_OFFSET (MonoContext, rip), 8); amd64_mov_reg_reg (code, AMD64_RSP, AMD64_R8, 8); /* jump to the saved IP */ amd64_jump_reg (code, AMD64_R11); nacl_global_codeman_validate(&start, 256, &code); mono_arch_flush_icache (start, code - start); mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL); if (info) *info = mono_tramp_info_create ("restore_context", start, code - start, ji, unwind_ops); return start; }
void mono_arch_patch_callsite (guint8 *method_start, guint8 *orig_code, guint8 *addr) { gint32 displace; unsigned short opcode; opcode = *((unsigned short *) (orig_code - 2)); if (opcode == 0x0dee) { /* This should be a 'iihf/iilf' sequence */ S390_EMIT_CALL((orig_code - 14), addr); mono_arch_flush_icache (orig_code - 14, 12); } else { /* This is the 'brasl' instruction */ orig_code -= 4; displace = ((gssize) addr - (gssize) (orig_code - 2)) / 2; s390_patch_rel (orig_code, displace); mono_arch_flush_icache (orig_code, 4); } }
/* * mono_arch_get_restore_context: * * Returns a pointer to a method which restores a previously saved sigcontext. */ gpointer mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot) { guint8 *start = NULL; guint8 *code; MonoJumpInfo *ji = NULL; GSList *unwind_ops = NULL; /* restore_contect (MonoContext *ctx) */ start = code = mono_global_codeman_reserve (256); amd64_mov_reg_reg (code, AMD64_R11, AMD64_ARG_REG1, 8); /* Restore all registers except %rip and %r11 */ amd64_mov_reg_membase (code, AMD64_RAX, AMD64_R11, G_STRUCT_OFFSET (MonoContext, rax), 8); amd64_mov_reg_membase (code, AMD64_RCX, AMD64_R11, G_STRUCT_OFFSET (MonoContext, rcx), 8); amd64_mov_reg_membase (code, AMD64_RDX, AMD64_R11, G_STRUCT_OFFSET (MonoContext, rdx), 8); amd64_mov_reg_membase (code, AMD64_RBX, AMD64_R11, G_STRUCT_OFFSET (MonoContext, rbx), 8); amd64_mov_reg_membase (code, AMD64_RBP, AMD64_R11, G_STRUCT_OFFSET (MonoContext, rbp), 8); amd64_mov_reg_membase (code, AMD64_RSI, AMD64_R11, G_STRUCT_OFFSET (MonoContext, rsi), 8); amd64_mov_reg_membase (code, AMD64_RDI, AMD64_R11, G_STRUCT_OFFSET (MonoContext, rdi), 8); //amd64_mov_reg_membase (code, AMD64_R8, AMD64_R11, G_STRUCT_OFFSET (MonoContext, r8), 8); //amd64_mov_reg_membase (code, AMD64_R9, AMD64_R11, G_STRUCT_OFFSET (MonoContext, r9), 8); //amd64_mov_reg_membase (code, AMD64_R10, AMD64_R11, G_STRUCT_OFFSET (MonoContext, r10), 8); amd64_mov_reg_membase (code, AMD64_R12, AMD64_R11, G_STRUCT_OFFSET (MonoContext, r12), 8); amd64_mov_reg_membase (code, AMD64_R13, AMD64_R11, G_STRUCT_OFFSET (MonoContext, r13), 8); amd64_mov_reg_membase (code, AMD64_R14, AMD64_R11, G_STRUCT_OFFSET (MonoContext, r14), 8); #if !defined(__native_client_codegen__) amd64_mov_reg_membase (code, AMD64_R15, AMD64_R11, G_STRUCT_OFFSET (MonoContext, r15), 8); #endif if (mono_running_on_valgrind ()) { /* Prevent 'Address 0x... is just below the stack ptr.' errors */ amd64_mov_reg_membase (code, AMD64_R8, AMD64_R11, G_STRUCT_OFFSET (MonoContext, rsp), 8); amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11, G_STRUCT_OFFSET (MonoContext, rip), 8); amd64_mov_reg_reg (code, AMD64_RSP, AMD64_R8, 8); } else { amd64_mov_reg_membase (code, AMD64_RSP, AMD64_R11, G_STRUCT_OFFSET (MonoContext, rsp), 8); /* get return address */ amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11, G_STRUCT_OFFSET (MonoContext, rip), 8); } /* jump to the saved IP */ amd64_jump_reg (code, AMD64_R11); nacl_global_codeman_validate(&start, 256, &code); mono_arch_flush_icache (start, code - start); if (info) *info = mono_tramp_info_create (g_strdup_printf ("restore_context"), start, code - start, ji, unwind_ops); return start; }
gpointer mono_arch_get_throw_exception_by_name (void) { guint8 *start, *code; int size = 64; /* Not used on MIPS */ start = code = mono_global_codeman_reserve (size); mips_break (code, 0xfd); mono_arch_flush_icache (start, code - start); return start; }
/** * mono_arch_get_throw_corlib_exception: * * Returns a function pointer which can be used to raise * corlib exceptions. The returned function has the following * signature: void (*func) (guint32 ex_token, guint32 offset); * Here, offset is the offset which needs to be substracted from the caller IP * to get the IP of the throw. Passing the offset has the advantage that it * needs no relocations in the caller. */ gpointer mono_arch_get_throw_corlib_exception (MonoTrampInfo **info, gboolean aot) { static guint32 *start; static int inited = 0; guint32 *code; int reg; g_assert (!aot); if (info) *info = NULL; if (inited) return start; inited = 1; code = start = mono_global_codeman_reserve (64 * sizeof (guint32)); #ifdef SPARCV9 reg = sparc_g4; #else reg = sparc_g1; #endif sparc_mov_reg_reg (code, sparc_o7, sparc_o2); sparc_save_imm (code, sparc_sp, -160, sparc_sp); sparc_set (code, MONO_TOKEN_TYPE_DEF, sparc_o7); sparc_add (code, FALSE, sparc_i0, sparc_o7, sparc_o1); sparc_set (code, mono_defaults.exception_class->image, sparc_o0); sparc_set (code, mono_exception_from_token, sparc_o7); sparc_jmpl (code, sparc_o7, sparc_g0, sparc_callsite); sparc_nop (code); /* Return to the caller, so exception handling does not see this frame */ sparc_restore (code, sparc_o0, sparc_g0, sparc_o0); /* Compute throw ip */ sparc_sll_imm (code, sparc_o1, 2, sparc_o1); sparc_sub (code, 0, sparc_o2, sparc_o1, sparc_o7); sparc_set (code, mono_arch_get_throw_exception (NULL, FALSE), reg); /* Use a jmp instead of a call so o7 is preserved */ sparc_jmpl_imm (code, reg, 0, sparc_g0); sparc_nop (code); g_assert ((code - start) < 32); mono_arch_flush_icache ((guint8*)start, (guint8*)code - (guint8*)start); return start; }
gpointer mono_arch_get_throw_exception_by_name (void) { guint8 *start, *code; int size = 64; /* Not used on MIPS */ start = code = mono_global_codeman_reserve (size); mips_break (code, 0xfd); mono_arch_flush_icache (start, code - start); MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL)); return start; }
/* * mono_arch_get_restore_context: * * Returns a pointer to a method which restores a previously saved sigcontext. */ gpointer mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot) { guint8 *start = NULL; guint8 *code; MonoJumpInfo *ji = NULL; GSList *unwind_ops = NULL; int i, gregs_offset; /* restore_contect (MonoContext *ctx) */ start = code = (guint8 *)mono_global_codeman_reserve (256); amd64_mov_reg_reg (code, AMD64_R11, AMD64_ARG_REG1, 8); /* Restore all registers except %rip and %r11 */ gregs_offset = MONO_STRUCT_OFFSET (MonoContext, gregs); for (i = 0; i < AMD64_NREG; ++i) { #if defined(__native_client_codegen__) if (i == AMD64_R15) continue; #endif if (i != AMD64_RIP && i != AMD64_RSP && i != AMD64_R8 && i != AMD64_R9 && i != AMD64_R10 && i != AMD64_R11) amd64_mov_reg_membase (code, i, AMD64_R11, gregs_offset + (i * 8), 8); } /* * The context resides on the stack, in the stack frame of the * caller of this function. The stack pointer that we need to * restore is potentially many stack frames higher up, so the * distance between them can easily be more than the red zone * size. Hence the stack pointer can be restored only after * we have finished loading everything from the context. */ amd64_mov_reg_membase (code, AMD64_R8, AMD64_R11, gregs_offset + (AMD64_RSP * 8), 8); amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11, gregs_offset + (AMD64_RIP * 8), 8); amd64_mov_reg_reg (code, AMD64_RSP, AMD64_R8, 8); /* jump to the saved IP */ amd64_jump_reg (code, AMD64_R11); nacl_global_codeman_validate (&start, 256, &code); mono_arch_flush_icache (start, code - start); mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL); if (info) *info = mono_tramp_info_create ("restore_context", start, code - start, ji, unwind_ops); return start; }
MonoContinuationRestore mono_tasklets_arch_restore (void) { static guint8* saved = NULL; guint8 *code, *start; int cont_reg = AMD64_R9; /* register usable on both call conventions */ const guint kMaxCodeSize = 64; if (saved) return (MonoContinuationRestore)saved; code = start = (guint8 *)mono_global_codeman_reserve (kMaxCodeSize); /* the signature is: restore (MonoContinuation *cont, int state, MonoLMF **lmf_addr) */ /* cont is in AMD64_ARG_REG1 ($rcx or $rdi) * state is in AMD64_ARG_REG2 ($rdx or $rsi) * lmf_addr is in AMD64_ARG_REG3 ($r8 or $rdx) * We move cont to cont_reg since we need both rcx and rdi for the copy * state is moved to $rax so it's setup as the return value and we can overwrite $rsi */ amd64_mov_reg_reg (code, cont_reg, MONO_AMD64_ARG_REG1, 8); amd64_mov_reg_reg (code, AMD64_RAX, MONO_AMD64_ARG_REG2, 8); /* setup the copy of the stack */ amd64_mov_reg_membase (code, AMD64_RCX, cont_reg, MONO_STRUCT_OFFSET (MonoContinuation, stack_used_size), sizeof (int)); amd64_shift_reg_imm (code, X86_SHR, AMD64_RCX, 3); x86_cld (code); amd64_mov_reg_membase (code, AMD64_RSI, cont_reg, MONO_STRUCT_OFFSET (MonoContinuation, saved_stack), sizeof (gpointer)); amd64_mov_reg_membase (code, AMD64_RDI, cont_reg, MONO_STRUCT_OFFSET (MonoContinuation, return_sp), sizeof (gpointer)); amd64_prefix (code, X86_REP_PREFIX); amd64_movsl (code); /* now restore the registers from the LMF */ amd64_mov_reg_membase (code, AMD64_RCX, cont_reg, MONO_STRUCT_OFFSET (MonoContinuation, lmf), 8); amd64_mov_reg_membase (code, AMD64_RBP, AMD64_RCX, MONO_STRUCT_OFFSET (MonoLMF, rbp), 8); amd64_mov_reg_membase (code, AMD64_RSP, AMD64_RCX, MONO_STRUCT_OFFSET (MonoLMF, rsp), 8); #ifdef WIN32 amd64_mov_reg_reg (code, AMD64_R14, AMD64_ARG_REG3, 8); #else amd64_mov_reg_reg (code, AMD64_R12, AMD64_ARG_REG3, 8); #endif /* state is already in rax */ amd64_jump_membase (code, cont_reg, MONO_STRUCT_OFFSET (MonoContinuation, return_ip)); g_assert ((code - start) <= kMaxCodeSize); mono_arch_flush_icache (start, code - start); mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL); saved = start; return (MonoContinuationRestore)saved; }
void mono_arch_patch_callsite (guint8 *method_start, guint8 *orig_code, guint8 *addr) { gint32 displace; unsigned short opcode; opcode = *((unsigned short *) (orig_code - 6)); /* This should be a 'brasl' instruction */ g_assert (opcode == 0xc0e5); orig_code -= 4; displace = ((gint32) addr - (gint32) (orig_code - 2)) / 2; s390_patch (orig_code, displace); mono_arch_flush_icache (orig_code, 4); }
gpointer mono_arch_get_unbox_trampoline (MonoMethod *m, gpointer addr) { guint8 *buf = mono_domain_code_reserve (mono_domain_get (), 64), *code = buf; // Pass the argument in a0. code = mono_riscv_emit_imm (code, RISCV_A0, sizeof (MonoObject)); code = mono_riscv_emit_imm (code, RISCV_T0, (gsize) addr); riscv_jalr (code, RISCV_ZERO, RISCV_T0, 0); mono_arch_flush_icache (buf, code - buf); return buf; }
gpointer mono_arch_get_static_rgctx_trampoline (gpointer arg, gpointer addr) { guint8 *buf = mono_domain_code_reserve (mono_domain_get (), 64), *code = buf; // Pass the argument in the RGCTX register. code = mono_riscv_emit_imm (code, MONO_ARCH_RGCTX_REG, (gsize) arg); code = mono_riscv_emit_imm (code, RISCV_T0, (gsize) addr); riscv_jalr (code, RISCV_ZERO, RISCV_T0, 0); mono_arch_flush_icache (buf, code - buf); return buf; }
gpointer mono_arch_create_handler_block_trampoline (MonoTrampInfo **info, gboolean aot) { guint8 *tramp = mono_get_trampoline_code (MONO_TRAMPOLINE_HANDLER_BLOCK_GUARD); guint8 *code, *buf; int tramp_size = 64; MonoJumpInfo *ji = NULL; GSList *unwind_ops = NULL; g_assert (!aot); code = buf = mono_global_codeman_reserve (tramp_size); /* * This trampoline restore the call chain of the handler block * then jumps into the code that deals with it. */ if (mono_get_jit_tls_offset () != -1) { s390_ear (code, s390_r1, 0); s390_sllg (code, s390_r1, s390_r1, 0, 32); s390_ear (code, s390_r1, 1); S390_SET (code, s390_r14, mono_get_jit_tls_offset()); s390_lg (code, s390_r14, s390_r1, 0, G_STRUCT_OFFSET(MonoJitTlsData, handler_block_return_address)); /* * Simulate a call */ S390_SET (code, s390_r1, tramp); s390_br (code, s390_r1); } else { /* * Slow path uses a C helper */ S390_SET (code, s390_r2, tramp); S390_SET (code, s390_r1, handler_block_trampoline_helper); s390_br (code, s390_r1); } mono_arch_flush_icache (buf, code - buf); if (mono_profiler_events & MONO_PROFILE_JIT_COMPILATION) mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_HELPER, NULL); g_assert (code - buf <= tramp_size); *info = mono_tramp_info_create ("handler_block_trampoline", buf, code - buf, ji, unwind_ops); return buf; }
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); switch (tramp_type) { /* * Monitor tramps have the object in r2 */ case MONO_TRAMPOLINE_MONITOR_ENTER: case MONO_TRAMPOLINE_MONITOR_ENTER_V4: case MONO_TRAMPOLINE_MONITOR_EXIT: s390_lgr (buf, s390_r1, s390_r2); break; /* * Generic class trampoline arg is in r2 */ case MONO_TRAMPOLINE_GENERIC_CLASS_INIT: s390_lgr (buf, s390_r1, s390_r2); break; default : S390_SET (buf, s390_r1, arg1); } displace = (tramp - buf) / 2; s390_jg (buf, displace); /* Flush instruction cache, since we've generated code */ mono_arch_flush_icache (code, buf - code); mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_SPECIFIC_TRAMPOLINE, (void *) mono_get_generic_trampoline_simple_name (tramp_type)); /* Sanity check */ g_assert ((buf - code) <= SPECIFIC_TRAMPOLINE_SIZE); if (code_len) *code_len = buf - code; return code; }
gpointer mono_arch_get_nullified_class_init_trampoline (MonoTrampInfo **info) { guint8 *buf, *code; code = buf = mono_global_codeman_reserve (16); sparc_ret (code); mono_arch_flush_icache (buf, code - buf); *info = mono_tramp_info_create ("nullified_class_init_trampoline", buf, code - buf, NULL, NULL); return buf; }