From f3bb4fb663ce6ca20b6565178cbd1f3980ccfab1 Mon Sep 17 00:00:00 2001 From: Johan Lorensson Date: Fri, 5 Jul 2019 10:30:17 +0200 Subject: [PATCH] Interpreter reads last error to late after pinvoke. (mono/mono#15571) * Interpreter reads last error to late after pinvoke. This could lead to clobbered last error since interpreter loop needs to run two additional IL instructions in order to read out the value. This works on JIT since the lowering saving the last error will happen right after pinvoke. This fix makes sure interpreter will get needed information to read out last error right after pinvoke (if requested). It adds a new IL prefix issued in managed->native wrapper that will tell codegen (and interpreter) that upcoming calli instruction needs to save last error, meaning that it could be done right after issuing the call, no need to run any additional IL instructions to do that work, closing the gap between the return of pinvoke call and save of last error. Should fix, https://github.com/mono/mono/issues/15541. * Optimize emit_get_last_error. Commit migrated from https://github.com/mono/mono/commit/b1b61d7cb7f580f5e5438a756ef3e67a5a832eeb --- src/mono/mono/cil/cil-opcodes.xml | 2 +- src/mono/mono/cil/opcode.def | 2 +- src/mono/mono/metadata/marshal-ilgen.c | 45 +++++++++++++--------------------- src/mono/mono/mini/cpu-x86.md | 2 ++ src/mono/mono/mini/interp/interp.c | 28 +++++++++++++-------- src/mono/mono/mini/interp/mintops.def | 4 +-- src/mono/mono/mini/interp/transform.c | 29 +++++++++++++++------- src/mono/mono/mini/method-to-ir.c | 26 ++++++++++++++------ src/mono/mono/mini/mini-amd64.c | 7 ++---- src/mono/mono/mini/mini-x86.c | 26 ++++++++++++++++++++ 10 files changed, 108 insertions(+), 63 deletions(-) diff --git a/src/mono/mono/cil/cil-opcodes.xml b/src/mono/mono/cil/cil-opcodes.xml index f65b16d..d1c6145 100644 --- a/src/mono/mono/cil/cil-opcodes.xml +++ b/src/mono/mono/cil/cil-opcodes.xml @@ -319,7 +319,7 @@ - + diff --git a/src/mono/mono/cil/opcode.def b/src/mono/mono/cil/opcode.def index 99e7be81..c23ccd6 100644 --- a/src/mono/mono/cil/opcode.def +++ b/src/mono/mono/cil/opcode.def @@ -319,7 +319,7 @@ OPDEF(CEE_MONO_LDPTR_NURSERY_BITS, "mono_ldptr_nursery_bits", Pop0, PushI, Inlin OPDEF(CEE_MONO_CALLI_EXTRA_ARG, "mono_calli_extra_arg", VarPop, VarPush, InlineSig, 0, 2, 0xF0, 0x18, CALL) OPDEF(CEE_MONO_LDDOMAIN, "mono_lddomain", Pop0, PushI, InlineNone, 0, 2, 0xF0, 0x19, NEXT) OPDEF(CEE_MONO_ATOMIC_STORE_I4, "mono_atomic_store_i4", PopI+PopI, Push0, InlineI, 0, 2, 0xF0, 0x1A, NEXT) -OPDEF(CEE_MONO_GET_LAST_ERROR, "mono_get_last_error", Pop0, PushI, InlineNone, 0, 2, 0xF0, 0x1B, NEXT) +OPDEF(CEE_MONO_SAVE_LAST_ERROR, "mono_save_last_error", Pop0, Push0, InlineNone, 0, 2, 0xF0, 0x1B, NEXT) OPDEF(CEE_MONO_GET_RGCTX_ARG, "mono_get_rgctx_arg", Pop0, PushI, InlineNone, 0, 2, 0xF0, 0x1C, NEXT) OPDEF(CEE_MONO_LDPTR_PROFILER_ALLOCATION_COUNT, "mono_ldptr_profiler_allocation_count", Pop0, PushI, InlineNone, 0, 2, 0xF0, 0x1D, NEXT) OPDEF(CEE_MONO_LD_DELEGATE_METHOD_PTR, "mono_ld_delegate_method_ptr", Pop1, PushI, InlineNone, 0, 2, 0xF0, 0x1E, NEXT) diff --git a/src/mono/mono/metadata/marshal-ilgen.c b/src/mono/mono/metadata/marshal-ilgen.c index ea478d1..468a690 100644 --- a/src/mono/mono/metadata/marshal-ilgen.c +++ b/src/mono/mono/metadata/marshal-ilgen.c @@ -1949,10 +1949,18 @@ emit_native_wrapper_ilgen (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSi mono_mb_emit_byte (mb, CEE_LDARG_0); mono_mb_emit_op (mb, CEE_UNBOX, mono_defaults.int_class); mono_mb_emit_byte (mb, CEE_LDIND_I); + if (piinfo->piflags & PINVOKE_ATTRIBUTE_SUPPORTS_LAST_ERROR) { + mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); + mono_mb_emit_byte (mb, CEE_MONO_SAVE_LAST_ERROR); + } mono_mb_emit_calli (mb, csig); } else if (MONO_CLASS_IS_IMPORT (mb->method->klass)) { #ifndef DISABLE_COM mono_mb_emit_ldloc (mb, gc_safe_transition_builder.coop_cominterop_fnptr); + if (piinfo->piflags & PINVOKE_ATTRIBUTE_SUPPORTS_LAST_ERROR) { + mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); + mono_mb_emit_byte (mb, CEE_MONO_SAVE_LAST_ERROR); + } mono_mb_emit_cominterop_call_function_pointer (mb, csig); #else g_assert_not_reached (); @@ -1962,37 +1970,18 @@ emit_native_wrapper_ilgen (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSi /* Reuse the ICALL_ADDR opcode for pinvokes too */ mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); mono_mb_emit_op (mb, CEE_MONO_ICALL_ADDR, &piinfo->method); - mono_mb_emit_calli (mb, csig); - } else { - mono_mb_emit_native_call (mb, csig, func); - } - } - - /* Set LastError if needed */ - if (piinfo->piflags & PINVOKE_ATTRIBUTE_SUPPORTS_LAST_ERROR) { -#ifdef TARGET_WIN32 - if (!aot) { - static MonoMethodSignature *get_last_error_sig = NULL; - if (!get_last_error_sig) { - get_last_error_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 0); - get_last_error_sig->ret = int_type; - get_last_error_sig->pinvoke = 1; + if (piinfo->piflags & PINVOKE_ATTRIBUTE_SUPPORTS_LAST_ERROR) { + mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); + mono_mb_emit_byte (mb, CEE_MONO_SAVE_LAST_ERROR); } - - /* - * Have to call GetLastError () early and without a wrapper, since various runtime components could - * clobber its value. - */ - mono_mb_emit_native_call (mb, get_last_error_sig, GetLastError); - mono_mb_emit_icall (mb, mono_marshal_set_last_error_windows); + mono_mb_emit_calli (mb, csig); } else { - mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - mono_mb_emit_byte (mb, CEE_MONO_GET_LAST_ERROR); - mono_mb_emit_icall (mb, mono_marshal_set_last_error_windows); + if (piinfo->piflags & PINVOKE_ATTRIBUTE_SUPPORTS_LAST_ERROR) { + mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); + mono_mb_emit_byte (mb, CEE_MONO_SAVE_LAST_ERROR); + } + mono_mb_emit_native_call (mb, csig, func); } -#else - mono_mb_emit_icall (mb, mono_marshal_set_last_error); -#endif } if (MONO_TYPE_ISSTRUCT (sig->ret)) { diff --git a/src/mono/mono/mini/cpu-x86.md b/src/mono/mono/mini/cpu-x86.md index e43586d..dd76612 100644 --- a/src/mono/mono/mini/cpu-x86.md +++ b/src/mono/mono/mini/cpu-x86.md @@ -674,3 +674,5 @@ get_sp: dest:i len:6 set_sp: src1:i len:6 fill_prof_call_ctx: src1:i len:128 + +get_last_error: dest:i len:32 diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c index f235324..5f07193 100644 --- a/src/mono/mono/mini/interp/interp.c +++ b/src/mono/mono/mini/interp/interp.c @@ -1349,7 +1349,7 @@ interp_to_native_trampoline (gpointer addr, gpointer ccontext) #pragma optimize ("", off) #endif static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE void -ves_pinvoke_method (InterpFrame *frame, MonoMethodSignature *sig, MonoFuncV addr, gboolean string_ctor, ThreadContext *context) +ves_pinvoke_method (InterpFrame *frame, MonoMethodSignature *sig, MonoFuncV addr, gboolean string_ctor, ThreadContext *context, gboolean save_last_error) { MonoLMFExt ext; gpointer args; @@ -1381,6 +1381,8 @@ ves_pinvoke_method (InterpFrame *frame, MonoMethodSignature *sig, MonoFuncV addr INTERP_PUSH_LMF_WITH_CTX (frame, ext, exit_pinvoke); entry_func ((gpointer) addr, args); + if (save_last_error) + mono_marshal_set_last_error (); interp_pop_lmf (&ext); #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP @@ -1878,7 +1880,7 @@ interp_entry (InterpEntryData *data) } static stackval * -do_icall (InterpFrame *frame, MonoMethodSignature *sig, int op, stackval *sp, gpointer ptr) +do_icall (InterpFrame *frame, MonoMethodSignature *sig, int op, stackval *sp, gpointer ptr, gboolean save_last_error) { switch (op) { case MINT_ICALL_V_V: { @@ -1981,6 +1983,9 @@ do_icall (InterpFrame *frame, MonoMethodSignature *sig, int op, stackval *sp, gp g_assert_not_reached (); } + if (save_last_error) + mono_marshal_set_last_error (); + /* convert the native representation to the stackval representation */ if (sig) stackval_from_data (sig->ret, &sp [-1], (char*) &sp [-1].data.p, sig->pinvoke); @@ -1993,12 +1998,12 @@ do_icall (InterpFrame *frame, MonoMethodSignature *sig, int op, stackval *sp, gp #pragma optimize ("", off) #endif static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE stackval * -do_icall_wrapper (InterpFrame *frame, MonoMethodSignature *sig, int op, stackval *sp, gpointer ptr) +do_icall_wrapper (InterpFrame *frame, MonoMethodSignature *sig, int op, stackval *sp, gpointer ptr, gboolean save_last_error) { MonoLMFExt ext; INTERP_PUSH_LMF_WITH_CTX (frame, ext, exit_icall); - sp = do_icall (frame, sig, op, sp, ptr); + sp = do_icall (frame, sig, op, sp, ptr, save_last_error); interp_pop_lmf (&ext); @@ -3177,25 +3182,28 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, FrameClause gpointer target_ip = sp [-1].data.p; MonoMethodSignature *csignature = (MonoMethodSignature*)imethod->data_items [* (guint16 *)(ip + 1)]; int opcode = *(guint16 *)(ip + 2); + gboolean save_last_error = *(guint16 *)(ip + 3); sp--; frame->ip = ip; - sp = do_icall_wrapper (frame, csignature, opcode, sp, target_ip); + sp = do_icall_wrapper (frame, csignature, opcode, sp, target_ip, save_last_error); EXCEPTION_CHECKPOINT; CHECK_RESUME_STATE (context); - ip += 3; + ip += 4; MINT_IN_BREAK; } MINT_IN_CASE(MINT_CALLI_NAT) { MonoMethodSignature *csignature; stackval *endsp = sp; unsigned char *code = NULL; + gboolean save_last_error = FALSE; frame->ip = ip; csignature = (MonoMethodSignature*)imethod->data_items [* (guint16 *)(ip + 1)]; - ip += 2; + save_last_error = *(guint16 *)(ip + 2); + ip += 3; --sp; --endsp; code = (guchar*)sp->data.p; @@ -3229,7 +3237,7 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, FrameClause interp_exec_method (&child_frame, context); } else { - ves_pinvoke_method (&child_frame, csignature, (MonoFuncV) code, FALSE, context); + ves_pinvoke_method (&child_frame, csignature, (MonoFuncV) code, FALSE, context, save_last_error); } CHECK_RESUME_STATE (context); @@ -5716,7 +5724,7 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, FrameClause * to check the abort threshold. For this to work we use child_frame as a * dummy frame that is stored in the lmf and serves as the transition frame */ - do_icall_wrapper (&child_frame, NULL, MINT_ICALL_V_P, &tmp_sp, (gpointer)mono_thread_get_undeniable_exception); + do_icall_wrapper (&child_frame, NULL, MINT_ICALL_V_P, &tmp_sp, (gpointer)mono_thread_get_undeniable_exception, FALSE); MonoException *abort_exc = (MonoException*)tmp_sp.data.p; if (abort_exc) @@ -5746,7 +5754,7 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, FrameClause MINT_IN_CASE(MINT_ICALL_PPPPPP_V) MINT_IN_CASE(MINT_ICALL_PPPPPP_P) frame->ip = ip; - sp = do_icall_wrapper (frame, NULL, *ip, sp, imethod->data_items [*(guint16 *)(ip + 1)]); + sp = do_icall_wrapper (frame, NULL, *ip, sp, imethod->data_items [*(guint16 *)(ip + 1)], FALSE); EXCEPTION_CHECKPOINT; CHECK_RESUME_STATE (context); ip += 2; diff --git a/src/mono/mono/mini/interp/mintops.def b/src/mono/mono/mini/interp/mintops.def index 40a243d..89a37ba 100644 --- a/src/mono/mono/mini/interp/mintops.def +++ b/src/mono/mono/mini/interp/mintops.def @@ -339,8 +339,8 @@ OPDEF(MINT_VCALLVIRT, "vcallvirt", 2, MintOpMethodToken) OPDEF(MINT_CALLVIRT_FAST, "callvirt.fast", 3, MintOpMethodToken) OPDEF(MINT_VCALLVIRT_FAST, "vcallvirt.fast", 3, MintOpMethodToken) OPDEF(MINT_CALLI, "calli", 2, MintOpMethodToken) -OPDEF(MINT_CALLI_NAT, "calli.nat", 2, MintOpMethodToken) -OPDEF(MINT_CALLI_NAT_FAST, "calli.nat.fast", 3, MintOpMethodToken) +OPDEF(MINT_CALLI_NAT, "calli.nat", 3, MintOpMethodToken) +OPDEF(MINT_CALLI_NAT_FAST, "calli.nat.fast", 4, MintOpMethodToken) OPDEF(MINT_CALL_VARARG, "call.vararg", 3, MintOpMethodToken) OPDEF(MINT_JMP, "jmp", 2, MintOpMethodToken) diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index 33e56aa..15d491e 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -1816,7 +1816,7 @@ interp_constrained_box (TransformData *td, MonoDomain *domain, MonoClass *constr /* Return FALSE if error, including inline failure */ static gboolean -interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target_method, MonoDomain *domain, MonoGenericContext *generic_context, unsigned char *is_bb_start, MonoClass *constrained_class, gboolean readonly, MonoError *error, gboolean check_visibility) +interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target_method, MonoDomain *domain, MonoGenericContext *generic_context, unsigned char *is_bb_start, MonoClass *constrained_class, gboolean readonly, MonoError *error, gboolean check_visibility, gboolean save_last_error) { MonoImage *image = m_class_get_image (method->klass); MonoMethodSignature *csignature; @@ -2128,8 +2128,13 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target if (calli) { td->last_ins->data [0] = get_data_item_index (td, (void *)csignature); - if (op != -1) - td->last_ins->data [1] = op; + if (op != -1) { + td->last_ins->data[1] = op; + if (td->last_ins->opcode == MINT_CALLI_NAT_FAST) + td->last_ins->data[2] = save_last_error; + } else if (op == -1 && td->last_ins->opcode == MINT_CALLI_NAT) { + td->last_ins->data[1] = save_last_error; + } } else { td->last_ins->data [0] = get_data_item_index (td, (void *)mono_interp_get_imethod (domain, target_method, error)); return_val_if_nok (error, FALSE); @@ -2846,6 +2851,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, guint32 *arg_offsets = NULL; guint32 *local_offsets = NULL; InterpInst *last_seq_point = NULL; + gboolean save_last_error = FALSE; original_bb = bb = mono_basic_block_split (method, error, header); goto_if_nok (error, exit); @@ -3288,7 +3294,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, if (sym_seq_points && !mono_bitset_test_fast (seq_point_locs, td->ip + 5 - header->code)) need_seq_point = TRUE; - if (!interp_transform_call (td, method, NULL, domain, generic_context, td->is_bb_start, constrained_class, readonly, error, TRUE)) + if (!interp_transform_call (td, method, NULL, domain, generic_context, td->is_bb_start, constrained_class, readonly, error, TRUE, save_last_error)) goto exit; if (need_seq_point) { @@ -3309,6 +3315,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, constrained_class = NULL; readonly = FALSE; + save_last_error = FALSE; break; } case CEE_RET: { @@ -4203,7 +4210,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, target_method = mono_class_get_method_from_name_checked (klass, "Unbox", 1, 0, error); goto_if_nok (error, exit); /* td->ip is incremented by interp_transform_call */ - if (!interp_transform_call (td, method, target_method, domain, generic_context, td->is_bb_start, NULL, FALSE, error, FALSE)) + if (!interp_transform_call (td, method, target_method, domain, generic_context, td->is_bb_start, NULL, FALSE, error, FALSE, FALSE)) goto exit; /* * CEE_UNBOX needs to push address of vtype while Nullable.Unbox returns the value type @@ -4240,7 +4247,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, target_method = mono_class_get_method_from_name_checked (klass, "Unbox", 1, 0, error); goto_if_nok (error, exit); /* td->ip is incremented by interp_transform_call */ - if (!interp_transform_call (td, method, target_method, domain, generic_context, td->is_bb_start, NULL, FALSE, error, FALSE)) + if (!interp_transform_call (td, method, target_method, domain, generic_context, td->is_bb_start, NULL, FALSE, error, FALSE, FALSE)) goto exit; } else { interp_add_ins (td, MINT_UNBOX); @@ -4286,7 +4293,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, MonoMethod *wrapper = mono_marshal_get_ldflda_wrapper (field->type); /* td->ip is incremented by interp_transform_call */ - if (!interp_transform_call (td, method, wrapper, domain, generic_context, td->is_bb_start, NULL, FALSE, error, FALSE)) + if (!interp_transform_call (td, method, wrapper, domain, generic_context, td->is_bb_start, NULL, FALSE, error, FALSE, FALSE)) goto exit; } else #endif @@ -4568,7 +4575,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, MonoMethod *target_method = mono_class_get_method_from_name_checked (klass, "Box", 1, 0, error); goto_if_nok (error, exit); /* td->ip is incremented by interp_transform_call */ - if (!interp_transform_call (td, method, target_method, domain, generic_context, td->is_bb_start, NULL, FALSE, error, FALSE)) + if (!interp_transform_call (td, method, target_method, domain, generic_context, td->is_bb_start, NULL, FALSE, error, FALSE, FALSE)) goto exit; } else if (!m_class_is_valuetype (klass)) { /* already boxed, do nothing. */ @@ -5280,7 +5287,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, interp_add_ins (td, MINT_POP); td->last_ins->data [0] = 1; --td->sp; - if (!interp_transform_call (td, method, NULL, domain, generic_context, td->is_bb_start, NULL, FALSE, error, FALSE)) + if (!interp_transform_call (td, method, NULL, domain, generic_context, td->is_bb_start, NULL, FALSE, error, FALSE, FALSE)) goto exit; break; case CEE_MONO_JIT_ICALL_ADDR: { @@ -5424,6 +5431,10 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, ++td->sp; ++td->ip; break; + case CEE_MONO_SAVE_LAST_ERROR: + save_last_error = TRUE; + ++td->ip; + break; default: g_error ("transform.c: Unimplemented opcode: 0xF0 %02x at 0x%x\n", *td->ip, td->ip-header->code); } diff --git a/src/mono/mono/mini/method-to-ir.c b/src/mono/mono/mini/method-to-ir.c index 411e34a..3c3b11e 100644 --- a/src/mono/mono/mini/method-to-ir.c +++ b/src/mono/mono/mini/method-to-ir.c @@ -5920,6 +5920,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b guint32 token, ins_flag; MonoClass *klass; MonoClass *constrained_class = NULL; + gboolean save_last_error = FALSE; guchar *ip, *end, *target, *err_pos; MonoMethodSignature *sig; MonoGenericContext *generic_context = NULL; @@ -7780,6 +7781,21 @@ calli_end: *sp++ = ins; } + if (save_last_error) { + save_last_error = FALSE; +#ifdef TARGET_WIN32 + // Making icalls etc could clobber the value so emit inline code + // to read last error on Windows. + MONO_INST_NEW (cfg, ins, OP_GET_LAST_ERROR); + ins->dreg = alloc_dreg (cfg, STACK_I4); + ins->type = STACK_I4; + MONO_ADD_INS (cfg->cbb, ins); + mono_emit_jit_icall (cfg, mono_marshal_set_last_error_windows, &ins); +#else + mono_emit_jit_icall (cfg, mono_marshal_set_last_error, NULL); +#endif + } + if (keep_this_alive) { MonoInst *dummy_use; @@ -10555,15 +10571,11 @@ mono_ldptr: EMIT_NEW_PCONST (cfg, ins, cfg->compile_aot ? NULL : cfg->domain); *sp++ = ins; break; - case MONO_CEE_MONO_GET_LAST_ERROR: + case MONO_CEE_MONO_SAVE_LAST_ERROR: g_assert (method->wrapper_type != MONO_WRAPPER_NONE); - MONO_INST_NEW (cfg, ins, OP_GET_LAST_ERROR); - ins->dreg = alloc_dreg (cfg, STACK_I4); - ins->type = STACK_I4; - MONO_ADD_INS (cfg->cbb, ins); - - *sp++ = ins; + // Just an IL prefix, setting this flag, picked up by call instructions. + save_last_error = TRUE; break; case MONO_CEE_MONO_GET_RGCTX_ARG: g_assert (method->wrapper_type != MONO_WRAPPER_NONE); diff --git a/src/mono/mono/mini/mini-amd64.c b/src/mono/mono/mini/mini-amd64.c index 2776962..b08feee 100644 --- a/src/mono/mono/mini/mini-amd64.c +++ b/src/mono/mono/mini/mini-amd64.c @@ -3861,17 +3861,14 @@ emit_setup_lmf (MonoCompile *cfg, guint8 *code, gint32 lmf_offset, int cfa_offse #ifdef TARGET_WIN32 -#define TEB_LAST_ERROR_SLOT 0x30 -#define TEB_LAST_ERROR_OFFSET 0x068 +#define TEB_LAST_ERROR_OFFSET 0x68 static guint8* emit_get_last_error (guint8* code, int dreg) { /* Threads last error value is located in TEB_LAST_ERROR_OFFSET. */ x86_prefix (code, X86_GS_PREFIX); - amd64_mov_reg_mem (code, dreg, TEB_LAST_ERROR_SLOT, sizeof (gpointer)); - amd64_mov_reg_membase (code, dreg, dreg, TEB_LAST_ERROR_OFFSET, sizeof (guint32)); - + amd64_mov_reg_mem (code, dreg, TEB_LAST_ERROR_OFFSET, sizeof (guint32)); return code; } diff --git a/src/mono/mono/mini/mini-x86.c b/src/mono/mono/mini/mini-x86.c index 0e01cc8..7b61d5f 100644 --- a/src/mono/mono/mini/mini-x86.c +++ b/src/mono/mono/mini/mini-x86.c @@ -2293,6 +2293,29 @@ emit_setup_lmf (MonoCompile *cfg, guint8 *code, gint32 lmf_offset, int cfa_offse return code; } +#ifdef TARGET_WIN32 + +#define TEB_LAST_ERROR_OFFSET 0x34 + +static guint8* +emit_get_last_error (guint8* code, int dreg) +{ + /* Threads last error value is located in TEB_LAST_ERROR_OFFSET. */ + x86_prefix (code, X86_FS_PREFIX); + x86_mov_reg_mem (code, dreg, TEB_LAST_ERROR_OFFSET, sizeof (guint32)); + return code; +} + +#else + +static guint8* +emit_get_last_error (guint8* code, int dreg) +{ + g_assert_not_reached (); +} + +#endif + /* benchmark and set based on cpu */ #define LOOP_ALIGNMENT 8 #define bb_is_loop_start(bb) ((bb)->loop_body_start && (bb)->nesting) @@ -4856,6 +4879,9 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) x86_mov_membase_reg (code, ins->sreg1, MONO_STRUCT_OFFSET (MonoContext, esi), X86_ESI, sizeof (target_mgreg_t)); x86_mov_membase_reg (code, ins->sreg1, MONO_STRUCT_OFFSET (MonoContext, edi), X86_EDI, sizeof (target_mgreg_t)); break; + case OP_GET_LAST_ERROR: + code = emit_get_last_error (code, ins->dreg); + break; default: g_warning ("unknown opcode %s\n", mono_inst_name (ins->opcode)); g_assert_not_reached (); -- 2.7.4