+ 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 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);
+
+ /* 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);