[pypy-commit] pypy default: hg merge jit-get-errno
arigo
noreply at buildbot.pypy.org
Thu Jun 26 12:38:42 CEST 2014
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r72243:37c876808e80
Date: 2014-06-26 12:36 +0200
http://bitbucket.org/pypy/pypy/changeset/37c876808e80/
Log: hg merge jit-get-errno
Optimize the errno handling in the JIT, notably around external
function calls. Linux-only.
diff --git a/rpython/jit/backend/llsupport/test/ztranslation_test.py b/rpython/jit/backend/llsupport/test/ztranslation_test.py
--- a/rpython/jit/backend/llsupport/test/ztranslation_test.py
+++ b/rpython/jit/backend/llsupport/test/ztranslation_test.py
@@ -3,7 +3,7 @@
from rpython.rlib.jit import JitDriver, unroll_parameters, set_param
from rpython.rlib.jit import PARAMETERS, dont_look_inside
from rpython.rlib.jit import promote
-from rpython.rlib import jit_hooks
+from rpython.rlib import jit_hooks, rposix
from rpython.rlib.objectmodel import keepalive_until_here
from rpython.rlib.rthread import ThreadLocalReference
from rpython.jit.backend.detect_cpu import getcpuclass
@@ -24,6 +24,7 @@
# - full optimizer
# - floats neg and abs
# - threadlocalref_get
+ # - get_errno, set_errno
class Frame(object):
_virtualizable_ = ['i']
@@ -64,6 +65,8 @@
if k - abs(j): raise ValueError
if k - abs(-j): raise ValueError
if t.get().nine != 9: raise ValueError
+ rposix.set_errno(total)
+ if rposix.get_errno() != total: raise ValueError
return chr(total % 253)
#
from rpython.rtyper.lltypesystem import lltype, rffi
diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py
--- a/rpython/jit/backend/x86/assembler.py
+++ b/rpython/jit/backend/x86/assembler.py
@@ -2325,12 +2325,38 @@
ed = effectinfo.extradescrs[0]
assert isinstance(ed, ThreadLocalRefDescr)
addr1 = rffi.cast(lltype.Signed, ed.get_tlref_addr())
+ # 'addr1' is the address is the current thread, but we assume that
+ # it is a thread-local at a constant offset from %fs/%gs.
addr0 = stmtlocal.threadlocal_base()
addr = addr1 - addr0
assert rx86.fits_in_32bits(addr)
mc = self.mc
- mc.writechar(stmtlocal.SEGMENT_TL) # prefix
- mc.MOV_rj(resloc.value, addr)
+ mc.writechar(stmtlocal.SEGMENT_TL) # prefix: %fs or %gs
+ mc.MOV_rj(resloc.value, addr) # memory read
+
+ def get_set_errno(self, op, loc, issue_a_write):
+ # this function is only called on Linux
+ from rpython.jit.backend.x86 import stmtlocal
+ addr = stmtlocal.get_errno_tl()
+ assert rx86.fits_in_32bits(addr)
+ mc = self.mc
+ mc.writechar(stmtlocal.SEGMENT_TL) # prefix: %fs or %gs
+ # !!important: the *next* instruction must be the one using 'addr'!!
+ if issue_a_write:
+ if isinstance(loc, RegLoc):
+ mc.MOV32_jr(addr, loc.value) # memory write from reg
+ else:
+ assert isinstance(loc, ImmedLoc)
+ newvalue = loc.value
+ newvalue = rffi.cast(rffi.INT, newvalue)
+ newvalue = rffi.cast(lltype.Signed, newvalue)
+ mc.MOV32_ji(addr, newvalue) # memory write immediate
+ else:
+ assert isinstance(loc, RegLoc)
+ if IS_X86_32:
+ mc.MOV_rj(loc.value, addr) # memory read
+ elif IS_X86_64:
+ mc.MOVSX32_rj(loc.value, addr) # memory read, sign-extend
genop_discard_list = [Assembler386.not_implemented_op_discard] * rop._LAST
diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py
--- a/rpython/jit/backend/x86/regalloc.py
+++ b/rpython/jit/backend/x86/regalloc.py
@@ -693,6 +693,7 @@
self.perform_math(op, [loc0], loc0)
TLREF_SUPPORT = sys.platform.startswith('linux')
+ ERRNO_SUPPORT = sys.platform.startswith('linux')
def _consider_threadlocalref_get(self, op):
if self.TLREF_SUPPORT:
@@ -701,6 +702,22 @@
else:
self._consider_call(op)
+ def _consider_get_errno(self, op):
+ if self.ERRNO_SUPPORT:
+ resloc = self.force_allocate_reg(op.result)
+ self.assembler.get_set_errno(op, resloc, issue_a_write=False)
+ else:
+ self._consider_call(op)
+
+ def _consider_set_errno(self, op):
+ if self.ERRNO_SUPPORT:
+ # op.getarg(0) is the function set_errno; op.getarg(1) is
+ # the new errno value
+ loc0 = self.rm.make_sure_var_in_reg(op.getarg(1))
+ self.assembler.get_set_errno(op, loc0, issue_a_write=True)
+ else:
+ self._consider_call(op)
+
def _call(self, op, arglocs, force_store=[], guard_not_forced_op=None):
# we need to save registers on the stack:
#
@@ -780,6 +797,10 @@
return self._consider_math_sqrt(op)
if oopspecindex == EffectInfo.OS_THREADLOCALREF_GET:
return self._consider_threadlocalref_get(op)
+ if oopspecindex == EffectInfo.OS_GET_ERRNO:
+ return self._consider_get_errno(op)
+ if oopspecindex == EffectInfo.OS_SET_ERRNO:
+ return self._consider_set_errno(op)
self._consider_call(op)
def consider_call_may_force(self, op, guard_op):
diff --git a/rpython/jit/backend/x86/stmtlocal.py b/rpython/jit/backend/x86/stmtlocal.py
--- a/rpython/jit/backend/x86/stmtlocal.py
+++ b/rpython/jit/backend/x86/stmtlocal.py
@@ -21,6 +21,10 @@
asm("%s" : "=r"(result));
return result;
}
+static long pypy__get_errno_tl(void)
+{
+ return ((long)&errno) - pypy__threadlocal_base();
+}
''' % _instruction])
@@ -30,3 +34,10 @@
compilation_info=eci,
_nowrapper=True,
) #transactionsafe=True)
+
+get_errno_tl = rffi.llexternal(
+ 'pypy__get_errno_tl',
+ [], lltype.Signed,
+ compilation_info=eci,
+ _nowrapper=True,
+ ) #transactionsafe=True)
diff --git a/rpython/jit/codewriter/effectinfo.py b/rpython/jit/codewriter/effectinfo.py
--- a/rpython/jit/codewriter/effectinfo.py
+++ b/rpython/jit/codewriter/effectinfo.py
@@ -23,6 +23,8 @@
OS_SHRINK_ARRAY = 3 # rgc.ll_shrink_array
OS_DICT_LOOKUP = 4 # ll_dict_lookup
OS_THREADLOCALREF_GET = 5 # llop.threadlocalref_get
+ OS_GET_ERRNO = 6 # rposix.get_errno
+ OS_SET_ERRNO = 7 # rposix.set_errno
#
OS_STR_CONCAT = 22 # "stroruni.concat"
OS_STR_SLICE = 23 # "stroruni.slice"
diff --git a/rpython/jit/codewriter/jtransform.py b/rpython/jit/codewriter/jtransform.py
--- a/rpython/jit/codewriter/jtransform.py
+++ b/rpython/jit/codewriter/jtransform.py
@@ -438,6 +438,8 @@
elif oopspec_name.endswith('dict.lookup'):
# also ordereddict.lookup
prepare = self._handle_dict_lookup_call
+ elif oopspec_name.startswith('rposix.'):
+ prepare = self._handle_rposix_call
else:
prepare = self.prepare_builtin_call
try:
@@ -1898,6 +1900,16 @@
else:
raise NotImplementedError(oopspec_name)
+ def _handle_rposix_call(self, op, oopspec_name, args):
+ if oopspec_name == 'rposix.get_errno':
+ return self._handle_oopspec_call(op, args, EffectInfo.OS_GET_ERRNO,
+ EffectInfo.EF_CANNOT_RAISE)
+ elif oopspec_name == 'rposix.set_errno':
+ return self._handle_oopspec_call(op, args, EffectInfo.OS_SET_ERRNO,
+ EffectInfo.EF_CANNOT_RAISE)
+ else:
+ raise NotImplementedError(oopspec_name)
+
def rewrite_op_jit_force_quasi_immutable(self, op):
v_inst, c_fieldname = op.args
descr1 = self.cpu.fielddescrof(v_inst.concretetype.TO,
diff --git a/rpython/jit/codewriter/test/test_jtransform.py b/rpython/jit/codewriter/test/test_jtransform.py
--- a/rpython/jit/codewriter/test/test_jtransform.py
+++ b/rpython/jit/codewriter/test/test_jtransform.py
@@ -148,6 +148,8 @@
EI.OS_RAW_MALLOC_VARSIZE_CHAR: ([INT], ARRAYPTR),
EI.OS_RAW_FREE: ([ARRAYPTR], lltype.Void),
EI.OS_THREADLOCALREF_GET: ([], rclass.OBJECTPTR),
+ EI.OS_GET_ERRNO: ([], INT),
+ EI.OS_SET_ERRNO: ([INT], lltype.Void),
}
argtypes = argtypes[oopspecindex]
assert argtypes[0] == [v.concretetype for v in op.args[1:]]
@@ -156,7 +158,9 @@
assert extraeffect == EI.EF_ELIDABLE_CAN_RAISE
elif oopspecindex == EI.OS_RAW_MALLOC_VARSIZE_CHAR:
assert extraeffect == EI.EF_CAN_RAISE
- elif oopspecindex == EI.OS_RAW_FREE:
+ elif oopspecindex in (EI.OS_RAW_FREE,
+ EI.OS_GET_ERRNO,
+ EI.OS_SET_ERRNO):
assert extraeffect == EI.EF_CANNOT_RAISE
elif oopspecindex == EI.OS_THREADLOCALREF_GET:
assert extraeffect == EI.EF_LOOPINVARIANT
@@ -1320,6 +1324,38 @@
assert op0.args[2] == 'calldescr-%d' % OS_THREADLOCALREF_GET
assert op0.result == v2
+def test_get_errno():
+ # test that the oopspec is present and correctly transformed
+ from rpython.rlib import rposix
+ FUNC = lltype.FuncType([], lltype.Signed)
+ func = lltype.functionptr(FUNC, 'get_errno', _callable=rposix.get_errno)
+ v3 = varoftype(lltype.Signed)
+ op = SpaceOperation('direct_call', [const(func)], v3)
+ tr = Transformer(FakeCPU(), FakeBuiltinCallControl())
+ op1 = tr.rewrite_operation(op)
+ assert op1.opname == 'residual_call_r_i'
+ assert op1.args[0].value == func
+ assert op1.args[1] == ListOfKind('ref', [])
+ assert op1.args[2] == 'calldescr-%d' % effectinfo.EffectInfo.OS_GET_ERRNO
+ assert op1.result == v3
+
+def test_set_errno():
+ # test that the oopspec is present and correctly transformed
+ from rpython.rlib import rposix
+ FUNC = lltype.FuncType([lltype.Signed], lltype.Void)
+ func = lltype.functionptr(FUNC, 'set_errno', _callable=rposix.set_errno)
+ v1 = varoftype(lltype.Signed)
+ v3 = varoftype(lltype.Void)
+ op = SpaceOperation('direct_call', [const(func), v1], v3)
+ tr = Transformer(FakeCPU(), FakeBuiltinCallControl())
+ op1 = tr.rewrite_operation(op)
+ assert op1.opname == 'residual_call_ir_v'
+ assert op1.args[0].value == func
+ assert op1.args[1] == ListOfKind('int', [v1])
+ assert op1.args[2] == ListOfKind('ref', [])
+ assert op1.args[3] == 'calldescr-%d' % effectinfo.EffectInfo.OS_SET_ERRNO
+ assert op1.result == v3
+
def test_unknown_operation():
op = SpaceOperation('foobar', [], varoftype(lltype.Void))
tr = Transformer()
diff --git a/rpython/rlib/rposix.py b/rpython/rlib/rposix.py
--- a/rpython/rlib/rposix.py
+++ b/rpython/rlib/rposix.py
@@ -98,9 +98,11 @@
# the default wrapper for set_errno is not suitable for use in critical places
# like around GIL handling logic, so we provide our own wrappers.
+ at jit.oopspec("rposix.get_errno()")
def get_errno():
return intmask(_get_errno())
+ at jit.oopspec("rposix.set_errno(errno)")
def set_errno(errno):
_set_errno(rffi.cast(INT, errno))
More information about the pypy-commit
mailing list