Author: Armin Rigo <[email protected]>
Branch: errno-again
Changeset: r75420:0055b7f7e471
Date: 2015-01-18 12:34 +0100
http://bitbucket.org/pypy/pypy/changeset/0055b7f7e471/
Log: Possibly clarify some things and avoid a few redundant loads; also,
I can't understand if SetLastError is supposed to pop its argument
off the stack or not (as used here) so write a generic case.
diff --git a/rpython/jit/backend/x86/callbuilder.py
b/rpython/jit/backend/x86/callbuilder.py
--- a/rpython/jit/backend/x86/callbuilder.py
+++ b/rpython/jit/backend/x86/callbuilder.py
@@ -32,6 +32,8 @@
# arguments, we need to decrease esp temporarily
stack_max = PASS_ON_MY_FRAME
+ tlofs_reg = None
+ saved_stack_position_reg = None
result_value_saved_early = False
def __init__(self, assembler, fnloc, arglocs,
@@ -152,8 +154,35 @@
if not we_are_translated(): # for testing: we should not access
self.mc.ADD(ebp, imm(1)) # ebp any more
+ def get_tlofs_reg(self):
+ """Load the THREADLOCAL_OFS from the stack into a callee-saved
+ register. Further calls just return the same register, by assuming
+ it is indeed saved."""
+ assert self.is_call_release_gil
+ if self.tlofs_reg is None:
+ # pick a register saved across calls
+ if IS_X86_32:
+ self.tlofs_reg = esi
+ else:
+ self.tlofs_reg = r12
+ self.mc.MOV_rs(self.tlofs_reg.value,
+ THREADLOCAL_OFS - self.current_esp)
+ return self.tlofs_reg
+
+ def save_stack_position(self):
+ """Load the current 'esp' value into a callee-saved register.
+ Further calls just return the same register, by assuming it is
+ indeed saved."""
+ assert IS_X86_32
+ assert stdcall_or_cdecl and self.is_call_release_gil
+ if self.saved_stack_position_reg is None:
+ # pick a register saved across calls
+ self.saved_stack_position_reg = edi
+ self.mc.MOV(self.saved_stack_position_reg, esp)
+
def write_real_errno(self, save_err):
- tlofsreg = None
+ """This occurs just before emit_raw_call().
+ """
mc = self.mc
if handle_lasterror and (save_err & rffi.RFFI_READSAVED_LASTERROR):
@@ -165,11 +194,13 @@
assert isinstance(self, CallBuilder32) # Windows 32-bit only
#
rpy_lasterror = llerrno.get_rpy_lasterror_offset(self.asm.cpu)
- tlofsreg = edi # saved across the call to SetLastError
- mc.MOV_rs(edi.value, THREADLOCAL_OFS - self.current_esp)
- mc.PUSH_m((edi.value, rpy_lasterror))
+ tlofsreg = self.get_tlofs_reg() # => esi, callee-saved
+ self.save_stack_position() # => edi, callee-saved
+ mc.PUSH_m((tlofsreg.value, rpy_lasterror))
mc.CALL(imm(SetLastError_addr))
- mc.ADD_ri(esp.value, WORD)
+ # restore the stack position without assuming a particular
+ # calling convention of _SetLastError()
+ self.mc.MOV(esp, self.saved_stack_position_reg)
if save_err & rffi.RFFI_READSAVED_ERRNO:
# Just before a call, read 'rpy_errno' and write it into the
@@ -178,9 +209,7 @@
# pass the arguments on x86-64.
rpy_errno = llerrno.get_rpy_errno_offset(self.asm.cpu)
p_errno = llerrno.get_p_errno_offset(self.asm.cpu)
- if tlofsreg is None:
- tlofsreg = eax
- mc.MOV_rs(eax.value, THREADLOCAL_OFS - self.current_esp)
+ tlofsreg = self.get_tlofs_reg() # => esi or r12, callee-saved
if IS_X86_32:
tmpreg = edx
else:
@@ -191,27 +220,27 @@
elif save_err & rffi.RFFI_ZERO_ERRNO_BEFORE:
# Same, but write zero.
p_errno = llerrno.get_p_errno_offset(self.asm.cpu)
- if tlofsreg is None:
- tlofsreg = eax
- mc.MOV_rs(eax.value, THREADLOCAL_OFS - self.current_esp)
+ tlofsreg = self.get_tlofs_reg() # => esi or r12, callee-saved
mc.MOV_rm(eax.value, (tlofsreg.value, p_errno))
mc.MOV32_mi((eax.value, 0), 0)
def read_real_errno(self, save_err):
- esi_is_threadlocal_ofs = False
+ """This occurs after emit_raw_call() and after restore_stack_pointer().
+ """
mc = self.mc
if save_err & rffi.RFFI_SAVE_ERRNO:
# Just after a call, read the real 'errno' and save a copy of
# it inside our thread-local 'rpy_errno'. Most registers are
# free here, including the callee-saved ones, except 'ebx'.
+ # The tlofs register might have been loaded earlier and is
+ # callee-saved, so it does not need to be reloaded.
rpy_errno = llerrno.get_rpy_errno_offset(self.asm.cpu)
p_errno = llerrno.get_p_errno_offset(self.asm.cpu)
- mc.MOV_rs(esi.value, THREADLOCAL_OFS)
- mc.MOV_rm(edi.value, (esi.value, p_errno))
+ tlofsreg = self.get_tlofs_reg() # => esi or r12 (possibly reused)
+ mc.MOV_rm(edi.value, (tlofsreg.value, p_errno))
mc.MOV32_rm(edi.value, (edi.value, 0))
- mc.MOV32_mr((esi.value, rpy_errno), edi.value)
- esi_is_threadlocal_ofs = True
+ mc.MOV32_mr((tlofsreg.value, rpy_errno), edi.value)
if handle_lasterror and (save_err & rffi.RFFI_SAVE_LASTERROR):
from rpython.rlib.rwin32 import _GetLastError
@@ -219,13 +248,12 @@
assert isinstance(self, CallBuilder32) # Windows 32-bit only
#
rpy_lasterror = llerrno.get_rpy_lasterror_offset(self.asm.cpu)
- self.save_result_value(save_edx=True)
+ self.save_result_value(save_edx=True) # save eax/edx/xmm0
self.result_value_saved_early = True
mc.CALL(imm(GetLastError_addr))
#
- if not esi_is_threadlocal_ofs:
- mc.MOV_rs(esi.value, THREADLOCAL_OFS)
- mc.MOV32_mr((esi.value, rpy_lasterror), eax.value)
+ tlofsreg = self.get_tlofs_reg() # => esi (possibly reused)
+ mc.MOV32_mr((tlofsreg.value, rpy_lasterror), eax.value)
def move_real_result_and_call_reacqgil_addr(self, fastgil):
from rpython.jit.backend.x86 import rx86
@@ -383,15 +411,10 @@
# Dynamically accept both stdcall and cdecl functions.
# We could try to detect from pyjitpl which calling
# convention this particular function takes, which would
- # avoid these two extra MOVs... but later. Pick any
- # caller-saved register here except ebx (used for shadowstack).
- if IS_X86_32:
- free_caller_save_reg = edi
- else:
- free_caller_save_reg = r14
- self.mc.MOV(free_caller_save_reg, esp)
+ # avoid these two extra MOVs... but later.
+ self.save_stack_position() # => edi (possibly reused)
self.mc.CALL(self.fnloc)
- self.mc.MOV(esp, free_caller_save_reg)
+ self.mc.MOV(esp, self.saved_stack_position_reg)
else:
self.mc.CALL(self.fnloc)
if self.callconv != FFI_DEFAULT_ABI:
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit