Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZoltan Varga <vargaz@gmail.com>2016-01-27 01:33:34 +0300
committerZoltan Varga <vargaz@gmail.com>2016-01-27 01:33:44 +0300
commit1df9e44ea8512554d6ea7a62d77b3ed4ddc56667 (patch)
tree508ee209ccf304ca4c976d77017a01c18cba579f
parent229f1532943e8d2ca048638d6a38cf499fe5c7a3 (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.c4
-rw-r--r--mono/mini/mini-exceptions.c12
-rw-r--r--mono/mini/mini.h2
-rw-r--r--mono/mini/tramp-amd64.c69
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));