/* * get_throw_trampoline: * * Generate a call to mono_x86_throw_exception/ * mono_x86_throw_corlib_exception. * If LLVM is true, generate code which assumes the caller is LLVM generated code, * which doesn't push the arguments. */ static guint8* get_throw_trampoline (const char *name, gboolean rethrow, gboolean llvm, gboolean corlib, gboolean llvm_abs, gboolean resume_unwind, MonoTrampInfo **info, gboolean aot) { guint8 *start, *code, *labels [16]; int i, stack_size, stack_offset, arg_offsets [5], regs_offset; MonoJumpInfo *ji = NULL; GSList *unwind_ops = NULL; guint kMaxCodeSize = 192; start = code = mono_global_codeman_reserve (kMaxCodeSize); stack_size = 128; /* * On apple, the stack is misaligned by the pushing of the return address. */ if (!llvm && corlib) /* On OSX, we don't generate alignment code to save space */ stack_size += 4; else stack_size += MONO_ARCH_FRAME_ALIGNMENT - 4; /* * The stack looks like this: * <pc offset> (only if corlib is TRUE) * <exception object>/<type token> * <return addr> <- esp (unaligned on apple) */ unwind_ops = mono_arch_get_cie_program (); /* Alloc frame */ 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); arg_offsets [0] = 0; arg_offsets [1] = 4; arg_offsets [2] = 8; arg_offsets [3] = 12; regs_offset = 16; /* Save registers */ for (i = 0; i < X86_NREG; ++i) if (i != X86_ESP) x86_mov_membase_reg (code, X86_ESP, regs_offset + (i * 4), i, 4); /* Calculate the offset between the current sp and the sp of the caller */ if (llvm) { /* LLVM doesn't push the arguments */ stack_offset = stack_size + 4; } else { if (corlib) { /* Two arguments */ stack_offset = stack_size + 4 + 8; #ifdef __APPLE__ /* We don't generate stack alignment code on osx to save space */ #endif } else { /* One argument + stack alignment */ stack_offset = stack_size + 4 + 4; #ifdef __APPLE__ /* Pop the alignment added by OP_THROW too */ stack_offset += MONO_ARCH_FRAME_ALIGNMENT - 4; #else if (mono_do_x86_stack_align) stack_offset += MONO_ARCH_FRAME_ALIGNMENT - 4; #endif } } /* Save ESP */ x86_lea_membase (code, X86_EAX, X86_ESP, stack_offset); x86_mov_membase_reg (code, X86_ESP, regs_offset + (X86_ESP * 4), X86_EAX, 4); /* Clear fp stack */ labels [0] = code; x86_fnstsw (code); x86_shift_reg_imm (code, X86_SHR, X86_EAX, 11); x86_alu_reg_imm (code, X86_AND, X86_EAX, 7); x86_alu_reg_imm (code, X86_CMP, X86_EAX, 0); labels [1] = code; x86_branch8 (code, X86_CC_EQ, 0, FALSE); x86_fstp (code, 0); x86_jump_code (code, labels [0]); mono_x86_patch (labels [1], code); /* Set arg1 == regs */ x86_lea_membase (code, X86_EAX, X86_ESP, regs_offset); x86_mov_membase_reg (code, X86_ESP, arg_offsets [0], X86_EAX, 4); /* Set arg2 == exc/ex_token_index */ if (resume_unwind) x86_mov_reg_imm (code, X86_EAX, 0); else x86_mov_reg_membase (code, X86_EAX, X86_ESP, stack_size + 4, 4); x86_mov_membase_reg (code, X86_ESP, arg_offsets [1], X86_EAX, 4); /* Set arg3 == eip */ if (llvm_abs) x86_alu_reg_reg (code, X86_XOR, X86_EAX, X86_EAX); else x86_mov_reg_membase (code, X86_EAX, X86_ESP, stack_size, 4); x86_mov_membase_reg (code, X86_ESP, arg_offsets [2], X86_EAX, 4); /* Set arg4 == rethrow/pc_offset */ if (resume_unwind) { x86_mov_membase_imm (code, X86_ESP, arg_offsets [3], 0, 4); } else if (corlib) { x86_mov_reg_membase (code, X86_EAX, X86_ESP, stack_size + 8, 4); if (llvm_abs) { /* * The caller is LLVM code which passes the absolute address not a pc offset, * so compensate by passing 0 as 'ip' and passing the negated abs address as * the pc offset. */ x86_neg_reg (code, X86_EAX); } x86_mov_membase_reg (code, X86_ESP, arg_offsets [3], X86_EAX, 4); } else { x86_mov_membase_imm (code, X86_ESP, arg_offsets [3], rethrow, 4); } /* Make the call */ if (aot) { // This can be called from runtime code, which can't guarantee that // ebx contains the got address. // So emit the got address loading code too code = mono_arch_emit_load_got_addr (start, code, NULL, &ji); code = mono_arch_emit_load_aotconst (start, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, corlib ? "mono_x86_throw_corlib_exception" : "mono_x86_throw_exception"); x86_call_reg (code, X86_EAX); } else { x86_call_code (code, resume_unwind ? (gpointer)(mono_x86_resume_unwind) : (corlib ? (gpointer)mono_x86_throw_corlib_exception : (gpointer)mono_x86_throw_exception)); } x86_breakpoint (code); g_assert ((code - start) < kMaxCodeSize); if (info) *info = mono_tramp_info_create (name, 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); mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL); return start; }
/* * get_throw_trampoline: * * Generate a call to mono_x86_throw_exception/ * mono_x86_throw_corlib_exception. * If LLVM is true, generate code which assumes the caller is LLVM generated code, * which doesn't push the arguments. */ static guint8* get_throw_trampoline (const char *name, gboolean rethrow, gboolean llvm, gboolean corlib, gboolean llvm_abs, gboolean resume_unwind, MonoTrampInfo **info, gboolean aot) { guint8 *start, *code; int i, stack_size, stack_offset, arg_offsets [5], regs_offset; MonoJumpInfo *ji = NULL; GSList *unwind_ops = NULL; start = code = mono_global_codeman_reserve (128); stack_size = 128; /* * On apple, the stack is misaligned by the pushing of the return address. */ if (!llvm && corlib) /* On OSX, we don't generate alignment code to save space */ stack_size += 4; else stack_size += MONO_ARCH_FRAME_ALIGNMENT - 4; /* * The stack looks like this: * <pc offset> (only if corlib is TRUE) * <exception object>/<type token> * <return addr> <- esp (unaligned on apple) */ 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); /* Alloc frame */ 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); arg_offsets [0] = 0; arg_offsets [1] = 4; arg_offsets [2] = 8; arg_offsets [3] = 12; regs_offset = 16; /* Save registers */ for (i = 0; i < X86_NREG; ++i) if (i != X86_ESP) x86_mov_membase_reg (code, X86_ESP, regs_offset + (i * 4), i, 4); /* Calculate the offset between the current sp and the sp of the caller */ if (llvm) { /* LLVM doesn't push the arguments */ stack_offset = stack_size + 4; } else { if (corlib) { /* Two arguments */ stack_offset = stack_size + 4 + 8; #ifdef __APPLE__ /* We don't generate stack alignment code on osx to save space */ #endif } else { /* One argument */ stack_offset = stack_size + 4 + 4; #ifdef __APPLE__ /* Pop the alignment added by OP_THROW too */ stack_offset += MONO_ARCH_FRAME_ALIGNMENT - 4; #endif } } /* Save ESP */ x86_lea_membase (code, X86_EAX, X86_ESP, stack_offset); x86_mov_membase_reg (code, X86_ESP, regs_offset + (X86_ESP * 4), X86_EAX, 4); /* Set arg1 == regs */ x86_lea_membase (code, X86_EAX, X86_ESP, regs_offset); x86_mov_membase_reg (code, X86_ESP, arg_offsets [0], X86_EAX, 4); /* Set arg2 == exc/ex_token_index */ if (resume_unwind) x86_mov_reg_imm (code, X86_EAX, 0); else x86_mov_reg_membase (code, X86_EAX, X86_ESP, stack_size + 4, 4); x86_mov_membase_reg (code, X86_ESP, arg_offsets [1], X86_EAX, 4); /* Set arg3 == eip */ if (llvm_abs) x86_alu_reg_reg (code, X86_XOR, X86_EAX, X86_EAX); else x86_mov_reg_membase (code, X86_EAX, X86_ESP, stack_size, 4); x86_mov_membase_reg (code, X86_ESP, arg_offsets [2], X86_EAX, 4); /* Set arg4 == rethrow/pc_offset */ if (resume_unwind) { x86_mov_membase_imm (code, X86_ESP, arg_offsets [3], 0, 4); } else if (corlib) { x86_mov_reg_membase (code, X86_EAX, X86_ESP, stack_size + 8, 4); if (llvm_abs) { /* * The caller is LLVM code which passes the absolute address not a pc offset, * so compensate by passing 0 as 'ip' and passing the negated abs address as * the pc offset. */ x86_neg_reg (code, X86_EAX); } x86_mov_membase_reg (code, X86_ESP, arg_offsets [3], X86_EAX, 4); } else { x86_mov_membase_imm (code, X86_ESP, arg_offsets [3], rethrow, 4); } /* Make the call */ if (aot) { // This can be called from runtime code, which can't guarantee that // ebx contains the got address. // So emit the got address loading code too code = mono_arch_emit_load_got_addr (start, code, NULL, &ji); code = mono_arch_emit_load_aotconst (start, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, corlib ? "mono_x86_throw_corlib_exception" : "mono_x86_throw_exception"); x86_call_reg (code, X86_EAX); } else { x86_call_code (code, resume_unwind ? (mono_x86_resume_unwind) : (corlib ? (gpointer)mono_x86_throw_corlib_exception : (gpointer)mono_x86_throw_exception)); } x86_breakpoint (code); g_assert ((code - start) < 128); if (info) *info = mono_tramp_info_create (g_strdup (name), start, code - start, ji, unwind_ops); return start; }
guchar* mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInfo **info, gboolean aot) { const char *tramp_name; guint8 *buf, *code, *tramp, *br_ex_check; GSList *unwind_ops = NULL; MonoJumpInfo *ji = NULL; int i, offset, frame_size, regarray_offset, lmf_offset, caller_ip_offset, arg_offset; int cfa_offset; /* cfa = cfa_reg + cfa_offset */ code = buf = mono_global_codeman_reserve (256); /* Note that there is a single argument to the trampoline * and it is stored at: esp + pushed_args * sizeof (target_mgreg_t) * the ret address is at: esp + (pushed_args + 1) * sizeof (target_mgreg_t) */ /* Compute frame offsets relative to the frame pointer %ebp */ arg_offset = sizeof (target_mgreg_t); caller_ip_offset = 2 * sizeof (target_mgreg_t); offset = 0; offset += sizeof (MonoLMF); lmf_offset = -offset; offset += X86_NREG * sizeof (target_mgreg_t); regarray_offset = -offset; /* Argument area */ offset += 4 * sizeof (target_mgreg_t); frame_size = ALIGN_TO (offset, MONO_ARCH_FRAME_ALIGNMENT); /* ret addr and arg are on the stack */ cfa_offset = 2 * sizeof (target_mgreg_t); mono_add_unwind_op_def_cfa (unwind_ops, code, buf, X86_ESP, cfa_offset); // IP saved at CFA - 4 mono_add_unwind_op_offset (unwind_ops, code, buf, X86_NREG, -4); /* Allocate frame */ x86_push_reg (code, X86_EBP); cfa_offset += sizeof (target_mgreg_t); mono_add_unwind_op_def_cfa_offset (unwind_ops, code, buf, cfa_offset); mono_add_unwind_op_offset (unwind_ops, code, buf, X86_EBP, -cfa_offset); x86_mov_reg_reg (code, X86_EBP, X86_ESP); mono_add_unwind_op_def_cfa_reg (unwind_ops, code, buf, X86_EBP); /* There are three words on the stack, adding + 4 aligns the stack to 16, which is needed on osx */ x86_alu_reg_imm (code, X86_SUB, X86_ESP, frame_size + sizeof (target_mgreg_t)); /* Save all registers */ for (i = X86_EAX; i <= X86_EDI; ++i) { int reg = i; if (i == X86_EBP) { /* Save original ebp */ /* EAX is already saved */ x86_mov_reg_membase (code, X86_EAX, X86_EBP, 0, sizeof (target_mgreg_t)); reg = X86_EAX; } else if (i == X86_ESP) { /* Save original esp */ /* EAX is already saved */ x86_mov_reg_reg (code, X86_EAX, X86_EBP); /* Saved ebp + trampoline arg + return addr */ x86_alu_reg_imm (code, X86_ADD, X86_EAX, 3 * sizeof (target_mgreg_t)); reg = X86_EAX; } x86_mov_membase_reg (code, X86_EBP, regarray_offset + (i * sizeof (target_mgreg_t)), reg, sizeof (target_mgreg_t)); } /* Setup LMF */ /* eip */ if (tramp_type == MONO_TRAMPOLINE_JUMP) { x86_mov_membase_imm (code, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, eip), 0, sizeof (target_mgreg_t)); } else { x86_mov_reg_membase (code, X86_EAX, X86_EBP, caller_ip_offset, sizeof (target_mgreg_t)); x86_mov_membase_reg (code, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, eip), X86_EAX, sizeof (target_mgreg_t)); } /* method */ if ((tramp_type == MONO_TRAMPOLINE_JIT) || (tramp_type == MONO_TRAMPOLINE_JUMP)) { x86_mov_reg_membase (code, X86_EAX, X86_EBP, arg_offset, sizeof (target_mgreg_t)); x86_mov_membase_reg (code, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, method), X86_EAX, sizeof (target_mgreg_t)); } else { x86_mov_membase_imm (code, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, method), 0, sizeof (target_mgreg_t)); } /* esp */ x86_mov_reg_membase (code, X86_EAX, X86_EBP, regarray_offset + (X86_ESP * sizeof (target_mgreg_t)), sizeof (target_mgreg_t)); x86_mov_membase_reg (code, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, esp), X86_EAX, sizeof (target_mgreg_t)); /* callee save registers */ x86_mov_reg_membase (code, X86_EAX, X86_EBP, regarray_offset + (X86_EBX * sizeof (target_mgreg_t)), sizeof (target_mgreg_t)); x86_mov_membase_reg (code, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, ebx), X86_EAX, sizeof (target_mgreg_t)); x86_mov_reg_membase (code, X86_EAX, X86_EBP, regarray_offset + (X86_EDI * sizeof (target_mgreg_t)), sizeof (target_mgreg_t)); x86_mov_membase_reg (code, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, edi), X86_EAX, sizeof (target_mgreg_t)); x86_mov_reg_membase (code, X86_EAX, X86_EBP, regarray_offset + (X86_ESI * sizeof (target_mgreg_t)), sizeof (target_mgreg_t)); x86_mov_membase_reg (code, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, esi), X86_EAX, sizeof (target_mgreg_t)); x86_mov_reg_membase (code, X86_EAX, X86_EBP, regarray_offset + (X86_EBP * sizeof (target_mgreg_t)), sizeof (target_mgreg_t)); x86_mov_membase_reg (code, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, ebp), X86_EAX, sizeof (target_mgreg_t)); /* Push LMF */ /* get the address of lmf for the current thread */ if (aot) { code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, "mono_get_lmf_addr"); x86_call_reg (code, X86_EAX); } else { x86_call_code (code, mono_get_lmf_addr); } /* lmf->lmf_addr = lmf_addr (%eax) */ x86_mov_membase_reg (code, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr), X86_EAX, sizeof (target_mgreg_t)); /* lmf->previous_lmf = *(lmf_addr) */ x86_mov_reg_membase (code, X86_ECX, X86_EAX, 0, sizeof (target_mgreg_t)); /* Signal to mono_arch_unwind_frame () that this is a trampoline frame */ x86_alu_reg_imm (code, X86_ADD, X86_ECX, 1); x86_mov_membase_reg (code, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), X86_ECX, sizeof (target_mgreg_t)); /* *lmf_addr = lmf */ x86_lea_membase (code, X86_ECX, X86_EBP, lmf_offset); x86_mov_membase_reg (code, X86_EAX, 0, X86_ECX, sizeof (target_mgreg_t)); /* Call trampoline function */ /* Arg 1 - registers */ x86_lea_membase (code, X86_EAX, X86_EBP, regarray_offset); x86_mov_membase_reg (code, X86_ESP, (0 * sizeof (target_mgreg_t)), X86_EAX, sizeof (target_mgreg_t)); /* Arg2 - calling code */ if (tramp_type == MONO_TRAMPOLINE_JUMP) { x86_mov_membase_imm (code, X86_ESP, (1 * sizeof (target_mgreg_t)), 0, sizeof (target_mgreg_t)); } else { x86_mov_reg_membase (code, X86_EAX, X86_EBP, caller_ip_offset, sizeof (target_mgreg_t)); x86_mov_membase_reg (code, X86_ESP, (1 * sizeof (target_mgreg_t)), X86_EAX, sizeof (target_mgreg_t)); } /* Arg3 - trampoline argument */ x86_mov_reg_membase (code, X86_EAX, X86_EBP, arg_offset, sizeof (target_mgreg_t)); x86_mov_membase_reg (code, X86_ESP, (2 * sizeof (target_mgreg_t)), X86_EAX, sizeof (target_mgreg_t)); /* Arg4 - trampoline address */ // FIXME: x86_mov_membase_imm (code, X86_ESP, (3 * sizeof (target_mgreg_t)), 0, sizeof (target_mgreg_t)); #ifdef __APPLE__ /* check the stack is aligned after the ret ip is pushed */ /* x86_mov_reg_reg (code, X86_EDX, X86_ESP); x86_alu_reg_imm (code, X86_AND, X86_EDX, 15); x86_alu_reg_imm (code, X86_CMP, X86_EDX, 0); x86_branch_disp (code, X86_CC_Z, 3, FALSE); x86_breakpoint (code); */ #endif if (aot) { code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_TRAMPOLINE_FUNC_ADDR, GINT_TO_POINTER (tramp_type)); x86_call_reg (code, X86_EAX); } else { tramp = (guint8*)mono_get_trampoline_func (tramp_type); x86_call_code (code, tramp); } /* * Overwrite the trampoline argument with the address we need to jump to, * to free %eax. */ x86_mov_membase_reg (code, X86_EBP, arg_offset, X86_EAX, 4); /* Restore LMF */ x86_mov_reg_membase (code, X86_EAX, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr), sizeof (target_mgreg_t)); x86_mov_reg_membase (code, X86_ECX, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), sizeof (target_mgreg_t)); x86_alu_reg_imm (code, X86_SUB, X86_ECX, 1); x86_mov_membase_reg (code, X86_EAX, 0, X86_ECX, sizeof (target_mgreg_t)); /* Check for interruptions */ if (aot) { code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, "mono_thread_force_interruption_checkpoint_noraise"); x86_call_reg (code, X86_EAX); } else { x86_call_code (code, (guint8*)mono_thread_force_interruption_checkpoint_noraise); } x86_test_reg_reg (code, X86_EAX, X86_EAX); br_ex_check = code; x86_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. */ x86_leave (code); /* * The exception is in eax. * We are calling the throw trampoline used by OP_THROW, so we have to setup the * stack to look the same. * The stack contains the ret addr, and the trampoline argument, the throw trampoline * expects it to contain the ret addr and the exception. It also needs to be aligned * after the exception is pushed. */ /* Align stack */ x86_push_reg (code, X86_EAX); /* Push the exception */ x86_push_reg (code, X86_EAX); //x86_breakpoint (code); /* Push the original return value */ x86_push_membase (code, X86_ESP, 3 * 4); /* * 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, "rethrow_preserve_exception_addr"); } else { x86_mov_reg_imm (code, X86_ECX, (guint8*)mono_get_rethrow_preserve_exception_addr ()); } x86_mov_reg_membase (code, X86_ECX, X86_ECX, 0, sizeof (target_mgreg_t)); x86_jump_reg (code, X86_ECX); /* Normal case */ mono_x86_patch (br_ex_check, code); /* Restore registers */ for (i = X86_EAX; i <= X86_EDI; ++i) { if (i == X86_ESP || i == X86_EBP) continue; if (i == X86_EAX && tramp_type != MONO_TRAMPOLINE_AOT_PLT) continue; x86_mov_reg_membase (code, i, X86_EBP, regarray_offset + (i * 4), 4); } /* Restore frame */ x86_leave (code); cfa_offset -= sizeof (target_mgreg_t); mono_add_unwind_op_def_cfa (unwind_ops, code, buf, X86_ESP, cfa_offset); mono_add_unwind_op_same_value (unwind_ops, code, buf, X86_EBP); if (MONO_TRAMPOLINE_TYPE_MUST_RETURN (tramp_type)) { /* Load the value returned by the trampoline */ x86_mov_reg_membase (code, X86_EAX, X86_ESP, 0, 4); /* The trampoline returns normally, pop the trampoline argument */ x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4); cfa_offset -= sizeof (target_mgreg_t); mono_add_unwind_op_def_cfa_offset (unwind_ops, code, buf, cfa_offset); x86_ret (code); } else { x86_ret (code); } g_assert ((code - buf) <= 256); MONO_PROFILER_RAISE (jit_code_buffer, (buf, code - buf, MONO_PROFILER_CODE_BUFFER_HELPER, NULL)); tramp_name = mono_get_generic_trampoline_name (tramp_type); *info = mono_tramp_info_create (tramp_name, buf, code - buf, ji, unwind_ops); return buf; }
/* * get_throw_exception: * * Generate a call to mono_x86_throw_exception/ * mono_x86_throw_corlib_exception. * If LLVM is true, generate code which assumes the caller is LLVM generated code, * which doesn't push the arguments. */ static guint8* get_throw_exception (const char *name, gboolean rethrow, gboolean llvm, gboolean corlib) { guint8 *start, *code; GSList *unwind_ops = NULL; int i, stack_size, stack_offset, arg_offsets [5], regs_offset; start = code = mono_global_codeman_reserve (128); stack_size = 128; /* * On apple, the stack is misaligned by the pushing of the return address. */ if (!llvm && corlib) /* On OSX, we don't generate alignment code to save space */ stack_size += 4; else stack_size += MONO_ARCH_FRAME_ALIGNMENT - 4; /* * The stack looks like this: * <pc offset> (only if corlib is TRUE) * <exception object>/<type token> * <return addr> <- esp (unaligned on apple) */ 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); /* Alloc frame */ 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); arg_offsets [0] = 0; arg_offsets [1] = 4; arg_offsets [2] = 8; arg_offsets [3] = 12; regs_offset = 16; /* Save registers */ for (i = 0; i < X86_NREG; ++i) if (i != X86_ESP) x86_mov_membase_reg (code, X86_ESP, regs_offset + (i * 4), i, 4); /* Calculate the offset between the current sp and the sp of the caller */ if (llvm) { /* LLVM doesn't push the arguments */ stack_offset = stack_size + 4; } else { if (corlib) { /* Two arguments */ stack_offset = stack_size + 4 + 8; #ifdef __APPLE__ /* We don't generate stack alignment code on osx to save space */ #endif } else { /* One argument */ stack_offset = stack_size + 4 + 4; #ifdef __APPLE__ /* Pop the alignment added by OP_THROW too */ stack_offset += MONO_ARCH_FRAME_ALIGNMENT - 4; #endif } } /* Save ESP */ x86_lea_membase (code, X86_EAX, X86_ESP, stack_offset); x86_mov_membase_reg (code, X86_ESP, regs_offset + (X86_ESP * 4), X86_EAX, 4); /* Set arg1 == regs */ x86_lea_membase (code, X86_EAX, X86_ESP, regs_offset); x86_mov_membase_reg (code, X86_ESP, arg_offsets [0], X86_EAX, 4); /* Set arg2 == exc */ x86_mov_reg_membase (code, X86_EAX, X86_ESP, stack_size + 4, 4); x86_mov_membase_reg (code, X86_ESP, arg_offsets [1], X86_EAX, 4); /* Set arg3 == eip */ x86_mov_reg_membase (code, X86_EAX, X86_ESP, stack_size, 4); x86_mov_membase_reg (code, X86_ESP, arg_offsets [2], X86_EAX, 4); if (corlib) { /* Set arg4 == offset */ x86_mov_reg_membase (code, X86_EAX, X86_ESP, stack_size + 8, 4); x86_mov_membase_reg (code, X86_ESP, arg_offsets [3], X86_EAX, 4); } else { /* Set arg4 == rethrow */ x86_mov_membase_imm (code, X86_ESP, arg_offsets [3], rethrow, 4); } /* Make the call */ x86_call_code (code, corlib ? (gpointer)mono_x86_throw_corlib_exception : (gpointer)mono_x86_throw_exception); x86_breakpoint (code); g_assert ((code - start) < 128); mono_save_trampoline_xdebug_info (corlib ? "llvm_throw_corlib_exception_trampoline" : "llvm_throw_exception_trampoline", start, code - start, unwind_ops); return start; }