[pypy-commit] pypy errno-again: Write and pass test_call_release_gil_save_errno, the first test
arigo
noreply at buildbot.pypy.org
Thu Jan 15 11:07:21 CET 2015
Author: Armin Rigo <arigo at tunes.org>
Branch: errno-again
Changeset: r75337:de4fa7e98110
Date: 2015-01-15 11:07 +0100
http://bitbucket.org/pypy/pypy/changeset/de4fa7e98110/
Log: Write and pass test_call_release_gil_save_errno, the first test
about the errno handling in callbuilder.
diff --git a/rpython/jit/backend/llsupport/callbuilder.py b/rpython/jit/backend/llsupport/callbuilder.py
--- a/rpython/jit/backend/llsupport/callbuilder.py
+++ b/rpython/jit/backend/llsupport/callbuilder.py
@@ -42,9 +42,9 @@
self.pop_gcmap()
self.load_result()
- def emit_call_release_gil(self):
+ def emit_call_release_gil(self, save_err):
"""Emit a CALL_RELEASE_GIL, including calls to releasegil_addr
- and reacqgil_addr."""
+ and reacqgil_addr. 'save_err' is a combination of rffi.RFFI_*ERR*."""
fastgil = rffi.cast(lltype.Signed, rgil.gil_fetch_fastgil())
self.select_call_release_gil_mode()
self.prepare_arguments()
@@ -52,6 +52,7 @@
self.call_releasegil_addr_and_move_real_arguments(fastgil)
self.emit_raw_call()
self.restore_stack_pointer()
+ self.save_errno(save_err)
self.move_real_result_and_call_reacqgil_addr(fastgil)
self.pop_gcmap()
self.load_result()
@@ -62,6 +63,9 @@
def move_real_result_and_call_reacqgil_addr(self, fastgil):
raise NotImplementedError
+ def save_errno(self, save_err):
+ raise NotImplementedError
+
def select_call_release_gil_mode(self):
"""Overridden in CallBuilder64"""
self.is_call_release_gil = True
diff --git a/rpython/jit/backend/llsupport/llerrno.py b/rpython/jit/backend/llsupport/llerrno.py
new file mode 100644
--- /dev/null
+++ b/rpython/jit/backend/llsupport/llerrno.py
@@ -0,0 +1,41 @@
+from rpython.rtyper.lltypesystem import lltype, rffi
+from rpython.translator.tool.cbuild import ExternalCompilationInfo
+from rpython.jit.backend.llsupport.symbolic import WORD
+
+
+def get_debug_saved_errno(cpu):
+ return cpu._debug_errno_container[3]
+
+def set_debug_saved_errno(cpu, nerrno):
+ assert nerrno >= 0
+ cpu._debug_errno_container[3] = nerrno
+
+def get_rpy_errno_offset(cpu):
+ if cpu.translate_support_code:
+ from rpython.rlib import rthread
+ return rthread.tlfield_rpy_errno.offset
+ else:
+ return 3 * WORD
+
+def _fetch_addr_errno():
+ eci = ExternalCompilationInfo(
+ separate_module_sources=['''
+ #include <errno.h>
+ RPY_EXPORTED long fetch_addr_errno(void) {
+ return (long)(&errno);
+ }
+ '''])
+ func1_ptr = rffi.llexternal('fetch_addr_errno', [], lltype.Signed,
+ compilation_info=eci, _nowrapper=True)
+ return func1_ptr()
+
+def get_p_errno_offset(cpu):
+ if cpu.translate_support_code:
+ from rpython.rlib import rthread
+ return rthread.tlfield_p_errno.offset
+ else:
+ if cpu._debug_errno_container[2] == 0:
+ addr_errno = _fetch_addr_errno()
+ assert addr_errno != 0
+ cpu._debug_errno_container[2] = addr_errno
+ return 2 * WORD
diff --git a/rpython/jit/backend/llsupport/llmodel.py b/rpython/jit/backend/llsupport/llmodel.py
--- a/rpython/jit/backend/llsupport/llmodel.py
+++ b/rpython/jit/backend/llsupport/llmodel.py
@@ -62,6 +62,9 @@
self.floatarraydescr = ArrayDescr(ad.basesize, ad.itemsize,
ad.lendescr, FLAG_FLOAT)
self.setup()
+ self._debug_errno_container = lltype.malloc(
+ rffi.CArray(lltype.Signed), 5, flavor='raw', zero=True,
+ track_allocation=False)
def getarraydescr_for_frame(self, type):
if type == history.FLOAT:
@@ -259,7 +262,8 @@
ll_threadlocal_addr = llop.threadlocalref_addr(
llmemory.Address)
else:
- ll_threadlocal_addr = llmemory.NULL
+ ll_threadlocal_addr = rffi.cast(llmemory.Address,
+ self._debug_errno_container)
llop.gc_writebarrier(lltype.Void, ll_frame)
ll_frame = func(ll_frame, ll_threadlocal_addr)
finally:
diff --git a/rpython/jit/backend/test/runner_test.py b/rpython/jit/backend/test/runner_test.py
--- a/rpython/jit/backend/test/runner_test.py
+++ b/rpython/jit/backend/test/runner_test.py
@@ -2920,7 +2920,45 @@
['bad args, signature %r' % codes[1:]] + different_values)
def test_call_release_gil_save_errno(self):
- XXX
+ from rpython.translator.tool.cbuild import ExternalCompilationInfo
+ from rpython.rlib.libffi import types
+ from rpython.jit.backend.llsupport import llerrno
+ #
+ eci = ExternalCompilationInfo(
+ separate_module_sources=['''
+ #include <errno.h>
+ RPY_EXPORTED void test_call_release_gil_save_errno(void) {
+ errno = 42;
+ }
+ '''])
+ fn_name = 'test_call_release_gil_save_errno'
+ func1_ptr = rffi.llexternal(fn_name, [], lltype.Void,
+ compilation_info=eci, _nowrapper=True)
+ func1_adr = rffi.cast(lltype.Signed, func1_ptr)
+ calldescr = self.cpu._calldescr_dynamic_for_tests([], types.void)
+ #
+ for saveerr in [rffi.RFFI_ERR_NONE, rffi.RFFI_SAVE_ERRNO]:
+ faildescr = BasicFailDescr(1)
+ ops = [
+ ResOperation(rop.CALL_RELEASE_GIL,
+ [ConstInt(saveerr), ConstInt(func1_adr)], None,
+ descr=calldescr),
+ ResOperation(rop.GUARD_NOT_FORCED, [], None, descr=faildescr),
+ ResOperation(rop.FINISH, [], None, descr=BasicFinalDescr(0))
+ ]
+ ops[-2].setfailargs([])
+ looptoken = JitCellToken()
+ self.cpu.compile_loop([], ops, looptoken)
+ #
+ llerrno.set_debug_saved_errno(self.cpu, 24)
+ self.cpu.execute_token(looptoken)
+ result = llerrno.get_debug_saved_errno(self.cpu)
+ print 'saveerr =', saveerr, ': got result =', result
+ #
+ if saveerr == rffi.RFFI_SAVE_ERRNO:
+ assert result == 42 # from the C code
+ else:
+ assert result == 24 # not touched
def test_call_release_gil_readsaved_errno(self):
XXX
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
@@ -1917,7 +1917,9 @@
def _genop_call(self, op, arglocs, resloc, is_call_release_gil=False):
from rpython.jit.backend.llsupport.descr import CallDescr
- cb = callbuilder.CallBuilder(self, arglocs[2], arglocs[3:], resloc)
+ func_index = 2 + is_call_release_gil
+ cb = callbuilder.CallBuilder(self, arglocs[func_index],
+ arglocs[func_index+1:], resloc)
descr = op.getdescr()
assert isinstance(descr, CallDescr)
@@ -1932,7 +1934,9 @@
cb.ressign = signloc.value
if is_call_release_gil:
- cb.emit_call_release_gil()
+ saveerrloc = arglocs[2]
+ assert isinstance(saveerrloc, ImmedLoc)
+ cb.emit_call_release_gil(saveerrloc.value)
else:
cb.emit()
@@ -2345,8 +2349,9 @@
# This loads the stack location THREADLOCAL_OFS into a
# register, and then read the word at the given offset.
# It is only supported if 'translate_support_code' is
- # true; otherwise, the original call to the piece of assembler
- # was done with a dummy NULL value.
+ # true; otherwise, the execute_token() was done with a
+ # dummy value for the stack location THREADLOCAL_OFS
+ #
assert self.cpu.translate_support_code
assert isinstance(resloc, RegLoc)
self.mc.MOV_rs(resloc.value, THREADLOCAL_OFS)
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
@@ -3,13 +3,16 @@
from rpython.rlib.objectmodel import we_are_translated
from rpython.jit.metainterp.history import INT, FLOAT
from rpython.jit.backend.x86.arch import (WORD, IS_X86_64, IS_X86_32,
- PASS_ON_MY_FRAME, FRAME_FIXED_SIZE)
+ PASS_ON_MY_FRAME, FRAME_FIXED_SIZE,
+ THREADLOCAL_OFS)
from rpython.jit.backend.x86.regloc import (eax, ecx, edx, ebx, esp, ebp, esi,
xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, r8, r9, r10, r11, edi,
r12, r13, r14, r15, X86_64_SCRATCH_REG, X86_64_XMM_SCRATCH_REG,
RegLoc, RawEspLoc, RawEbpLoc, imm, ImmedLoc)
from rpython.jit.backend.x86.jump import remap_frame_layout
from rpython.jit.backend.llsupport.callbuilder import AbstractCallBuilder
+from rpython.jit.backend.llsupport import llerrno
+from rpython.rtyper.lltypesystem import rffi
# darwin requires the stack to be 16 bytes aligned on calls.
@@ -146,6 +149,19 @@
if not we_are_translated(): # for testing: we should not access
self.mc.ADD(ebp, imm(1)) # ebp any more
+ def save_errno(self, save_err):
+ 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'.
+ rpy_errno = llerrno.get_rpy_errno_offset(self.asm.cpu)
+ p_errno = llerrno.get_p_errno_offset(self.asm.cpu)
+ mc = self.mc
+ mc.MOV_rs(esi.value, THREADLOCAL_OFS)
+ mc.MOV_rm(edi.value, (esi.value, p_errno))
+ mc.MOV32_rm(edi.value, (edi.value, 0))
+ mc.MOV32_mr((esi.value, rpy_errno), edi.value)
+
def move_real_result_and_call_reacqgil_addr(self, fastgil):
from rpython.jit.backend.x86 import rx86
#
@@ -195,7 +211,8 @@
# in 'ebx'), and if not, we fall back to 'reacqgil_addr'.
mc.J_il8(rx86.Conditions['NE'], 0)
jne_location = mc.get_relative_pos()
- # here, ecx is zero (so rpy_fastgil was not acquired)
+ # here, ecx is zero (so rpy_fastgil was in 'released' state
+ # before the XCHG, but the XCHG acquired it by writing 1)
rst = gcrootmap.get_root_stack_top_addr()
mc = self.mc
mc.CMP(ebx, heap(rst))
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
@@ -743,10 +743,10 @@
else:
self.perform(op, arglocs, resloc)
- def _consider_call(self, op, guard_not_forced_op=None):
+ def _consider_call(self, op, guard_not_forced_op=None, first_arg_index=1):
calldescr = op.getdescr()
assert isinstance(calldescr, CallDescr)
- assert len(calldescr.arg_classes) == op.numargs() - 1
+ assert len(calldescr.arg_classes) == op.numargs() - first_arg_index
size = calldescr.get_result_size()
sign = calldescr.is_result_signed()
if sign:
@@ -795,8 +795,9 @@
self._consider_call(op, guard_op)
def consider_call_release_gil(self, op, guard_op):
+ # [Const(save_err), func_addr, args...]
assert guard_op is not None
- self._consider_call(op, guard_op)
+ self._consider_call(op, guard_op, first_arg_index=2)
def consider_call_malloc_gc(self, op):
self._consider_call(op)
More information about the pypy-commit
mailing list