diff options
author | Zoltan Varga <vargaz@gmail.com> | 2016-01-27 01:33:34 +0300 |
---|---|---|
committer | Zoltan Varga <vargaz@gmail.com> | 2016-01-27 01:33:44 +0300 |
commit | 1df9e44ea8512554d6ea7a62d77b3ed4ddc56667 (patch) | |
tree | 508ee209ccf304ca4c976d77017a01c18cba579f | |
parent | 229f1532943e8d2ca048638d6a38cf499fe5c7a3 (diff) |
[amd64] Change the way exceptions are thrown from trampolines: instead of calling mono_thread_force_interruption_checkpoint (), which would throw the exception using mono_raise_exception (), obtain the exception, unwind to the parent frame, and throw the exception normally there by calling the throw exception trampoline.
-rw-r--r-- | mono/mini/aot-runtime.c | 4 | ||||
-rw-r--r-- | mono/mini/mini-exceptions.c | 12 | ||||
-rw-r--r-- | mono/mini/mini.h | 2 | ||||
-rw-r--r-- | mono/mini/tramp-amd64.c | 69 |
4 files changed, 68 insertions, 19 deletions
diff --git a/mono/mini/aot-runtime.c b/mono/mini/aot-runtime.c index 28f72b83fb0..09e4b47943e 100644 --- a/mono/mini/aot-runtime.c +++ b/mono/mini/aot-runtime.c @@ -4862,6 +4862,8 @@ load_function_full (MonoAotModule *amodule, const char *name, MonoTrampInfo **ou target = mono_get_lmf_addr; } else if (!strcmp (ji->data.name, "mono_thread_force_interruption_checkpoint")) { target = mono_thread_force_interruption_checkpoint; + } else if (!strcmp (ji->data.name, "mono_thread_force_interruption_checkpoint_noraise")) { + target = mono_thread_force_interruption_checkpoint_noraise; } else if (!strcmp (ji->data.name, "mono_exception_from_token")) { target = mono_exception_from_token; } else if (!strcmp (ji->data.name, "mono_throw_exception")) { @@ -4884,6 +4886,8 @@ load_function_full (MonoAotModule *amodule, const char *name, MonoTrampInfo **ou target = debugger_agent_single_step_from_context; } else if (!strcmp (ji->data.name, "debugger_agent_breakpoint_from_context")) { target = debugger_agent_breakpoint_from_context; + } else if (!strcmp (ji->data.name, "throw_exception_addr")) { + target = mono_get_throw_exception_addr (); } else if (strstr (ji->data.name, "generic_trampoline_")) { target = mono_aot_get_trampoline (ji->data.name); } else if (aot_jit_icall_hash && g_hash_table_lookup (aot_jit_icall_hash, ji->data.name)) { diff --git a/mono/mini/mini-exceptions.c b/mono/mini/mini-exceptions.c index 797a9fd1484..95d110649ed 100644 --- a/mono/mini/mini-exceptions.c +++ b/mono/mini/mini-exceptions.c @@ -193,6 +193,18 @@ mono_get_throw_corlib_exception (void) return throw_corlib_exception_func; } +/* + * mono_get_throw_exception_addr: + * + * Return an address which stores the result of + * mono_get_throw_exception. + */ +gpointer +mono_get_throw_exception_addr (void) +{ + return &throw_exception_func; +} + static gboolean is_address_protected (MonoJitInfo *ji, MonoJitExceptionInfo *ei, gpointer ip) { diff --git a/mono/mini/mini.h b/mono/mini/mini.h index 37d5f08ebcc..5cf8fb55038 100644 --- a/mono/mini/mini.h +++ b/mono/mini/mini.h @@ -2827,7 +2827,7 @@ gpointer mono_get_call_filter (void); gpointer mono_get_restore_context (void); gpointer mono_get_throw_exception_by_name (void); gpointer mono_get_throw_corlib_exception (void); - +gpointer mono_get_throw_exception_addr (void); MonoArray *ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info); MonoBoolean ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info, MonoReflectionMethod **method, diff --git a/mono/mini/tramp-amd64.c b/mono/mini/tramp-amd64.c index 66b8bfa4c4e..a5ba7000e40 100644 --- a/mono/mini/tramp-amd64.c +++ b/mono/mini/tramp-amd64.c @@ -277,13 +277,13 @@ guchar* mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInfo **info, gboolean aot) { char *tramp_name; - guint8 *buf, *code, *tramp, *br [2], *r11_save_code, *after_r11_save_code; - int i, lmf_offset, offset, res_offset, arg_offset, rax_offset, tramp_offset, ctx_offset, saved_regs_offset; + guint8 *buf, *code, *tramp, *br [2], *r11_save_code, *after_r11_save_code, *br_ex_check; + int i, lmf_offset, offset, res_offset, arg_offset, rax_offset, ex_offset, tramp_offset, ctx_offset, saved_regs_offset; int r11_save_offset, saved_fpregs_offset, rbp_offset, framesize, orig_rsp_to_rbp_offset, cfa_offset; gboolean has_caller; GSList *unwind_ops = NULL; MonoJumpInfo *ji = NULL; - const guint kMaxCodeSize = NACL_SIZE (600, 600*2); + const guint kMaxCodeSize = NACL_SIZE (630, 630*2); #if defined(__native_client_codegen__) const guint kNaClTrampOffset = 17; @@ -304,6 +304,9 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf rax_offset = -offset; offset += sizeof(mgreg_t); + ex_offset = -offset; + + offset += sizeof(mgreg_t); r11_save_offset = -offset; offset += sizeof(mgreg_t); @@ -540,21 +543,7 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf amd64_mov_reg_imm (code, AMD64_R11, tramp); } amd64_call_reg (code, AMD64_R11); - - /* Check for thread interruption */ - /* This is not perf critical code so no need to check the interrupt flag */ - /* - * Have to call the _force_ variant, since there could be a protected wrapper on the top of the stack. - */ amd64_mov_membase_reg (code, AMD64_RBP, res_offset, AMD64_RAX, sizeof(mgreg_t)); - if (aot) { - code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, "mono_thread_force_interruption_checkpoint"); - } else { - amd64_mov_reg_imm (code, AMD64_R11, (guint8*)mono_thread_force_interruption_checkpoint); - } - amd64_call_reg (code, AMD64_R11); - - amd64_mov_reg_membase (code, AMD64_RAX, AMD64_RBP, res_offset, sizeof(mgreg_t)); /* Restore LMF */ amd64_mov_reg_membase (code, AMD64_RCX, AMD64_RBP, lmf_offset + MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), sizeof(gpointer)); @@ -566,8 +555,53 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf * Save rax to the stack, after the leave instruction, this will become part of * the red zone. */ + amd64_mov_reg_membase (code, AMD64_RAX, AMD64_RBP, res_offset, sizeof(mgreg_t)); amd64_mov_membase_reg (code, AMD64_RBP, rax_offset, AMD64_RAX, sizeof(mgreg_t)); + /* Check for thread interruption */ + /* This is not perf critical code so no need to check the interrupt flag */ + /* + * Have to call the _force_ variant, since there could be a protected wrapper on the top of the stack. + */ + if (aot) { + code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, "mono_thread_force_interruption_checkpoint_noraise"); + } else { + amd64_mov_reg_imm (code, AMD64_R11, (guint8*)mono_thread_force_interruption_checkpoint_noraise); + } + amd64_call_reg (code, AMD64_R11); + + amd64_test_reg_reg (code, AMD64_RAX, AMD64_RAX); + br_ex_check = code; + amd64_branch8 (code, X86_CC_Z, -1, 1); + + /* + * Exception case: + * We have an exception we want to throw in the caller's frame, so pop + * the trampoline frame and throw from the caller. + */ + amd64_leave (code); + /* We are in the parent frame, the exception is in rax */ + /* + * EH is initialized after trampolines, so get the address of the variable + * which contains throw_exception, and load it from there. + */ + if (aot) { + /* Not really a jit icall */ + code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, "throw_exception_addr"); + } else { + amd64_mov_reg_imm (code, AMD64_R11, (guint8*)mono_get_throw_exception_addr ()); + } + amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11, 0, sizeof(gpointer)); + amd64_mov_reg_reg (code, AMD64_ARG_REG1, AMD64_RAX, sizeof(mgreg_t)); + /* + * We still have the original return value on the top of the stack, so the + * throw trampoline will use that as the throw site. + */ + amd64_jump_reg (code, AMD64_R11); + + /* Normal case */ + mono_amd64_patch (br_ex_check, code); + /* Restore argument registers, r10 (imt method/rgxtx) and rax (needed for direct calls to C vararg functions). */ for (i = 0; i < AMD64_NREG; ++i) @@ -581,7 +615,6 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf cfa_offset -= sizeof (mgreg_t); mono_add_unwind_op_def_cfa (unwind_ops, code, buf, AMD64_RSP, cfa_offset); - if (MONO_TRAMPOLINE_TYPE_MUST_RETURN (tramp_type)) { /* Load result */ amd64_mov_reg_membase (code, AMD64_RAX, AMD64_RSP, rax_offset - sizeof(mgreg_t), sizeof(mgreg_t)); |