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_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; }
/* * 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_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); mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), 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; }
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; }
/* * 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; }
/* * mono_x86_get_signal_exception_trampoline: * * This x86 specific trampoline is used to call handle_signal_exception. */ gpointer mono_x86_get_signal_exception_trampoline (MonoTrampInfo **info, gboolean aot) { guint8 *start, *code; MonoJumpInfo *ji = NULL; GSList *unwind_ops = NULL; int stack_size; start = code = mono_global_codeman_reserve (128); /* Caller ip */ x86_push_reg (code, X86_ECX); mono_add_unwind_op_def_cfa (unwind_ops, (guint8*)NULL, (guint8*)NULL, X86_ESP, 4); mono_add_unwind_op_offset (unwind_ops, (guint8*)NULL, (guint8*)NULL, X86_NREG, -4); /* Fix the alignment to be what apple expects */ stack_size = 12; x86_alu_reg_imm (code, X86_SUB, X86_ESP, stack_size); mono_add_unwind_op_def_cfa_offset (unwind_ops, code, start, stack_size + 4); /* Arg1 */ x86_mov_membase_reg (code, X86_ESP, 0, X86_EAX, 4); /* Branch to target */ x86_call_reg (code, X86_EDX); g_assert ((code - start) < 128); if (info) *info = mono_tramp_info_create (g_strdup ("x86_signal_exception_trampoline"), start, code - start, ji, unwind_ops); 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; }
/* * 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; guint8 *code; MonoJumpInfo *ji = NULL; GSList *unwind_ops = NULL; /* call_filter (MonoContext *ctx, unsigned long eip) */ start = code = mono_global_codeman_reserve (64); x86_push_reg (code, X86_EBP); x86_mov_reg_reg (code, X86_EBP, X86_ESP, 4); x86_push_reg (code, X86_EBX); x86_push_reg (code, X86_EDI); x86_push_reg (code, X86_ESI); /* load ctx */ x86_mov_reg_membase (code, X86_EAX, X86_EBP, 8, 4); /* load eip */ x86_mov_reg_membase (code, X86_ECX, X86_EBP, 12, 4); /* save EBP */ x86_push_reg (code, X86_EBP); /* set new EBP */ x86_mov_reg_membase (code, X86_EBP, X86_EAX, G_STRUCT_OFFSET (MonoContext, ebp), 4); /* restore registers used by global register allocation (EBX & ESI) */ x86_mov_reg_membase (code, X86_EBX, X86_EAX, G_STRUCT_OFFSET (MonoContext, ebx), 4); x86_mov_reg_membase (code, X86_ESI, X86_EAX, G_STRUCT_OFFSET (MonoContext, esi), 4); x86_mov_reg_membase (code, X86_EDI, X86_EAX, G_STRUCT_OFFSET (MonoContext, edi), 4); /* align stack and save ESP */ x86_mov_reg_reg (code, X86_EDX, X86_ESP, 4); x86_alu_reg_imm (code, X86_AND, X86_ESP, -MONO_ARCH_FRAME_ALIGNMENT); g_assert (MONO_ARCH_FRAME_ALIGNMENT >= 8); x86_alu_reg_imm (code, X86_SUB, X86_ESP, MONO_ARCH_FRAME_ALIGNMENT - 8); x86_push_reg (code, X86_EDX); /* call the handler */ x86_call_reg (code, X86_ECX); /* restore ESP */ x86_pop_reg (code, X86_ESP); /* restore EBP */ x86_pop_reg (code, X86_EBP); /* restore saved regs */ x86_pop_reg (code, X86_ESI); x86_pop_reg (code, X86_EDI); x86_pop_reg (code, X86_EBX); x86_leave (code); x86_ret (code); if (info) *info = mono_tramp_info_create (g_strdup_printf ("call_filter"), start, code - start, ji, unwind_ops); g_assert ((code - start) < 64); 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; /* 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; }
/* * 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; }
/* * 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 (128); /* load ctx */ x86_mov_reg_membase (code, X86_EAX, X86_ESP, 4, 4); /* get return address, stored in ECX */ x86_mov_reg_membase (code, X86_ECX, X86_EAX, G_STRUCT_OFFSET (MonoContext, eip), 4); /* restore EBX */ x86_mov_reg_membase (code, X86_EBX, X86_EAX, G_STRUCT_OFFSET (MonoContext, ebx), 4); /* restore EDI */ x86_mov_reg_membase (code, X86_EDI, X86_EAX, G_STRUCT_OFFSET (MonoContext, edi), 4); /* restore ESI */ x86_mov_reg_membase (code, X86_ESI, X86_EAX, G_STRUCT_OFFSET (MonoContext, esi), 4); /* restore ESP */ x86_mov_reg_membase (code, X86_ESP, X86_EAX, G_STRUCT_OFFSET (MonoContext, esp), 4); /* save the return addr to the restored stack */ x86_push_reg (code, X86_ECX); /* restore EBP */ x86_mov_reg_membase (code, X86_EBP, X86_EAX, G_STRUCT_OFFSET (MonoContext, ebp), 4); /* restore ECX */ x86_mov_reg_membase (code, X86_ECX, X86_EAX, G_STRUCT_OFFSET (MonoContext, ecx), 4); /* restore EDX */ x86_mov_reg_membase (code, X86_EDX, X86_EAX, G_STRUCT_OFFSET (MonoContext, edx), 4); /* restore EAX */ x86_mov_reg_membase (code, X86_EAX, X86_EAX, G_STRUCT_OFFSET (MonoContext, eax), 4); /* jump to the saved IP */ x86_ret (code); nacl_global_codeman_validate(&start, 128, &code); if (info) *info = mono_tramp_info_create (g_strdup_printf ("restore_context"), start, code - start, ji, unwind_ops); else { GSList *l; for (l = unwind_ops; l; l = l->next) g_free (l->data); g_slist_free (unwind_ops); } 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; }
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_get_nullified_class_init_trampoline (MonoTrampInfo **info) { guint8 *buf, *code; code = buf = mono_global_codeman_reserve (16); s390_br (code, s390_r14); if (info) *info = mono_tramp_info_create ("nullified_class_init_trampoline", buf, code - buf, NULL, NULL); return (buf); }
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; }
gpointer mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot) { guint8 *start, *code; MonoJumpInfo *ji = NULL; GSList *unwind_ops = NULL; int i, ctx_reg, size; guint8 *labels [16]; size = 256; code = start = mono_global_codeman_reserve (size); arm_movx (code, ARMREG_IP0, ARMREG_R0); ctx_reg = ARMREG_IP0; /* Restore fregs */ arm_ldrx (code, ARMREG_IP1, ctx_reg, MONO_STRUCT_OFFSET (MonoContext, has_fregs)); labels [0] = code; arm_cbzx (code, ARMREG_IP1, 0); for (i = 0; i < 32; ++i) arm_ldrfpx (code, i, ctx_reg, MONO_STRUCT_OFFSET (MonoContext, fregs) + (i * 8)); mono_arm_patch (labels [0], code, MONO_R_ARM64_CBZ); /* Restore gregs */ // FIXME: Restore less registers // FIXME: fp should be restored later code = mono_arm_emit_load_regarray (code, 0xffffffff & ~(1 << ctx_reg) & ~(1 << ARMREG_SP), ctx_reg, MONO_STRUCT_OFFSET (MonoContext, regs)); /* ip0/ip1 doesn't need to be restored */ /* ip1 = pc */ arm_ldrx (code, ARMREG_IP1, ctx_reg, MONO_STRUCT_OFFSET (MonoContext, pc)); /* ip0 = sp */ arm_ldrx (code, ARMREG_IP0, ctx_reg, MONO_STRUCT_OFFSET (MonoContext, regs) + (ARMREG_SP * 8)); /* Restore sp, ctx is no longer valid */ arm_movspx (code, ARMREG_SP, ARMREG_IP0); /* Branch to pc */ arm_brx (code, ARMREG_IP1); /* Not reached */ arm_brk (code, 0); 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 ("restore_context", start, code - start, ji, unwind_ops); return start; }
/* * mono_x86_get_signal_exception_trampoline: * * This x86 specific trampoline is used to call handle_signal_exception. */ gpointer mono_x86_get_signal_exception_trampoline (MonoTrampInfo **info, gboolean aot) { guint8 *start, *code; MonoJumpInfo *ji = NULL; GSList *unwind_ops = NULL; int stack_size; start = code = mono_global_codeman_reserve (128); /* FIXME no unwind before we push ip */ /* Caller ip */ x86_push_reg (code, X86_ECX); mono_add_unwind_op_def_cfa (unwind_ops, code, start, X86_ESP, 4); mono_add_unwind_op_offset (unwind_ops, code, start, X86_NREG, -4); /* Fix the alignment to be what apple expects */ stack_size = 12; x86_alu_reg_imm (code, X86_SUB, X86_ESP, stack_size); mono_add_unwind_op_def_cfa_offset (unwind_ops, code, start, stack_size + 4); /* Arg1 */ x86_mov_membase_reg (code, X86_ESP, 0, X86_EAX, 4); /* Branch to target */ x86_call_reg (code, X86_EDX); g_assert ((code - start) < 128); if (info) *info = mono_tramp_info_create ("x86_signal_exception_trampoline", start, code - start, ji, unwind_ops); else { GSList *l; for (l = unwind_ops; l; l = l->next) g_free (l->data); g_slist_free (unwind_ops); } 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_EXCEPTION_HANDLING, NULL); return start; }
guchar * mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInfo **info, gboolean aot) { if (aot) NOT_IMPLEMENTED; guint8 *buf = mono_global_codeman_reserve (1024), *code = buf; if (info) { char *name = mono_get_generic_trampoline_name (tramp_type); *info = mono_tramp_info_create (name, buf, code - buf, NULL, NULL); g_free (name); } return buf; }
gpointer mono_arch_get_nullified_class_init_trampoline (MonoTrampInfo **info) { guint8 *buf, *code; code = buf = mono_global_codeman_reserve (16); s390_br (code, s390_r14); mono_arch_flush_icache (buf, code - buf); mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_HELPER, NULL); *info = mono_tramp_info_create ("nullified_class_init_trampoline", buf, code - buf, NULL, NULL); return (buf); }
/* * arch_get_restore_context: * * Returns a pointer to a method which restores a previously saved sigcontext. * The first argument in r0 is the pointer to the context. */ gpointer mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot) { guint8 *code; guint8 *start; int ctx_reg; MonoJumpInfo *ji = NULL; GSList *unwind_ops = NULL; start = code = mono_global_codeman_reserve (128); /* * Move things to their proper place so we can restore all the registers with * one instruction. */ ctx_reg = ARMREG_R0; #if defined(ARM_FPU_VFP) ARM_ADD_REG_IMM8 (code, ARMREG_IP, ctx_reg, G_STRUCT_OFFSET (MonoContext, fregs)); ARM_FLDMD (code, ARM_VFP_D0, 16, ARMREG_IP); #endif /* move pc to PC */ ARM_LDR_IMM (code, ARMREG_IP, ctx_reg, G_STRUCT_OFFSET (MonoContext, pc)); ARM_STR_IMM (code, ARMREG_IP, ctx_reg, G_STRUCT_OFFSET (MonoContext, regs) + (ARMREG_PC * sizeof (mgreg_t))); /* restore everything */ ARM_ADD_REG_IMM8 (code, ARMREG_IP, ctx_reg, G_STRUCT_OFFSET(MonoContext, regs)); ARM_LDM (code, ARMREG_IP, 0xffff); /* never reached */ ARM_DBRK (code); g_assert ((code - start) < 128); mono_arch_flush_icache (start, code - start); if (info) *info = mono_tramp_info_create ("restore_context", start, code - start, ji, unwind_ops); return start; }
/* * 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 *code; guint8* start; int ctx_reg; MonoJumpInfo *ji = NULL; GSList *unwind_ops = NULL; /* call_filter (MonoContext *ctx, unsigned long eip, gpointer exc) */ start = code = mono_global_codeman_reserve (320); /* save all the regs on the stack */ ARM_MOV_REG_REG (code, ARMREG_IP, ARMREG_SP); ARM_PUSH (code, MONO_ARM_REGSAVE_MASK); ARM_SUB_REG_IMM8 (code, ARMREG_SP, ARMREG_SP, 8); /* restore all the regs from ctx (in r0), but not sp, the stack pointer */ ctx_reg = ARMREG_R0; ARM_LDR_IMM (code, ARMREG_IP, ctx_reg, MONO_STRUCT_OFFSET (MonoContext, pc)); ARM_ADD_REG_IMM8 (code, ARMREG_LR, ctx_reg, MONO_STRUCT_OFFSET(MonoContext, regs) + (MONO_ARM_FIRST_SAVED_REG * sizeof (mgreg_t))); ARM_LDM (code, ARMREG_LR, MONO_ARM_REGSAVE_MASK); /* call handler at eip (r1) and set the first arg with the exception (r2) */ ARM_MOV_REG_REG (code, ARMREG_R0, ARMREG_R2); ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC); ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_R1); ARM_ADD_REG_IMM8 (code, ARMREG_SP, ARMREG_SP, 8); /* epilog */ ARM_POP_NWB (code, 0xff0 | ((1 << ARMREG_SP) | (1 << ARMREG_PC))); g_assert ((code - start) < 320); mono_arch_flush_icache (start, code - start); if (info) *info = mono_tramp_info_create ("call_filter", start, code - start, ji, unwind_ops); return start; }
gpointer mono_arch_create_generic_class_init_trampoline (MonoTrampInfo **info, gboolean aot) { guint8 *tramp; guint8 *code, *buf; static int byte_offset = -1; static guint8 bitmask; guint8 *jump; gint32 displace; int tramp_size; GSList *unwind_ops = NULL; MonoJumpInfo *ji = NULL; tramp_size = 48; code = buf = mono_global_codeman_reserve (tramp_size); unwind_ops = mono_arch_get_cie_program (); if (byte_offset < 0) mono_marshal_find_bitfield_offset (MonoVTable, initialized, &byte_offset, &bitmask); s390_llgc(code, s390_r0, 0, MONO_ARCH_VTABLE_REG, byte_offset); s390_nill(code, s390_r0, bitmask); s390_bnzr(code, s390_r14); tramp = mono_arch_create_specific_trampoline (NULL, MONO_TRAMPOLINE_GENERIC_CLASS_INIT, mono_get_root_domain (), NULL); /* jump to the actual trampoline */ displace = (tramp - code) / 2; s390_jg (code, displace); mono_arch_flush_icache (buf, code - buf); g_assert (code - buf <= tramp_size); if (info) *info = mono_tramp_info_create ("generic_class_init_trampoline", buf, code - buf, ji, unwind_ops); return(buf); }
gpointer mono_arch_create_rgctx_lazy_fetch_trampoline (guint32 slot, MonoTrampInfo **info, gboolean aot) { if (aot) NOT_IMPLEMENTED; gboolean is_mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot); int index = MONO_RGCTX_SLOT_INDEX (slot); if (is_mrgctx) index += MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (target_mgreg_t); int depth; for (depth = 0; ; depth++) { int size = mono_class_rgctx_get_array_size (depth, is_mrgctx); if (index < size - 1) break; index -= size - 1; } guint8 *buf = mono_global_codeman_reserve (128 * depth), *code = buf; guint8 **null_jumps = g_malloc0 (sizeof (guint8 *) * (depth + 2)); if (!is_mrgctx) { } else riscv_addi (code, RISCV_T1, RISCV_A0, 0); mono_arch_flush_icache (buf, code - buf); if (info) { char *name = mono_get_rgctx_fetch_trampoline_name (slot); *info = mono_tramp_info_create (name, buf, code - buf, NULL, NULL); g_free (name); } return buf; }
/* * arch_get_restore_context: * * Returns a pointer to a method which restores a previously saved sigcontext. * The first argument in r0 is the pointer to the context. */ gpointer mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot) { guint8 *code; guint8 *start; int ctx_reg; MonoJumpInfo *ji = NULL; GSList *unwind_ops = NULL; start = code = mono_global_codeman_reserve (128); /* * Move things to their proper place so we can restore all the registers with * one instruction. */ ctx_reg = ARMREG_R0; /* move eip to PC */ ARM_LDR_IMM (code, ARMREG_IP, ctx_reg, G_STRUCT_OFFSET (MonoContext, eip)); ARM_STR_IMM (code, ARMREG_IP, ctx_reg, G_STRUCT_OFFSET (MonoContext, regs) + (ARMREG_PC * 4)); /* move sp to SP */ ARM_LDR_IMM (code, ARMREG_IP, ctx_reg, G_STRUCT_OFFSET (MonoContext, esp)); ARM_STR_IMM (code, ARMREG_IP, ctx_reg, G_STRUCT_OFFSET (MonoContext, regs) + (ARMREG_SP * 4)); /* restore everything */ ARM_ADD_REG_IMM8 (code, ARMREG_IP, ctx_reg, G_STRUCT_OFFSET(MonoContext, regs)); ARM_LDM (code, ARMREG_IP, 0xffff); /* never reached */ ARM_DBRK (code); g_assert ((code - start) < 128); 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; }
/* * mono_arch_get_gsharedvt_arg_trampoline: * * See tramp-x86.c for documentation. */ gpointer mono_arch_get_gsharedvt_arg_trampoline (MonoDomain *domain, gpointer arg, gpointer addr) { guint8 *code, *start; int buf_len; buf_len = 32; start = code = mono_domain_code_reserve (domain, buf_len); amd64_mov_reg_imm (code, AMD64_RAX, arg); amd64_jump_code (code, addr); 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_GENERICS_TRAMPOLINE, NULL); mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), domain); 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 this_pos = 4, size = 16; MonoDomain *domain = mono_domain_get (); GSList *unwind_ops; start = code = mono_domain_code_reserve (domain, size); unwind_ops = mono_arch_get_cie_program (); x86_alu_membase_imm (code, X86_ADD, X86_ESP, this_pos, MONO_ABI_SIZEOF (MonoObject)); x86_jump_code (code, addr); g_assert ((code - start) < size); MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_UNBOX_TRAMPOLINE, m)); mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, unwind_ops), domain); 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_SET (code, s390_r1, addr); s390_aghi (code, this_pos, sizeof(MonoObject)); s390_br (code, s390_r1); g_assert ((code - start) <= 28); mono_arch_flush_icache (start, code - start); mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_UNBOX_TRAMPOLINE, method); mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), domain); return start; }
gpointer mono_arch_create_general_rgctx_lazy_fetch_trampoline (MonoTrampInfo **info, gboolean aot) { if (aot) NOT_IMPLEMENTED; guint8 *buf = mono_global_codeman_reserve (64), *code = buf; /* * The RGCTX register holds a pointer to a <slot, trampoline address> pair. * Load the trampoline address and branch to it. a0 holds the actual * (M)RGCTX or VTable. */ code = mono_riscv_emit_load (code, RISCV_T0, MONO_ARCH_RGCTX_REG, sizeof (target_mgreg_t)); riscv_jalr (code, RISCV_ZERO, RISCV_T0, 0); mono_arch_flush_icache (buf, code - buf); if (info) *info = mono_tramp_info_create ("rgctx_fetch_trampoline_general", buf, code - buf, NULL, NULL); return buf; }