Author: Armin Rigo <[email protected]>
Branch: portable-threadlocal
Changeset: r74650:5291d2692c23
Date: 2014-11-23 14:18 +0100
http://bitbucket.org/pypy/pypy/changeset/5291d2692c23/
Log: Clean up and adpat the JIT to the new threadlocals. Still missing:
optimization for OS_THREADLOCALREF_ADDR in the x86 and arm backends
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
@@ -2320,24 +2320,9 @@
assert isinstance(reg, RegLoc)
self.mc.MOV_rr(reg.value, ebp.value)
- def threadlocalref_get(self, op, resloc):
- # this function is only called on Linux
- from rpython.jit.codewriter.jitcode import ThreadLocalRefDescr
- from rpython.jit.backend.x86 import stmtlocal
+ def threadlocalref_addr(self, resloc):
assert isinstance(resloc, RegLoc)
- effectinfo = op.getdescr().get_extra_info()
- assert effectinfo.extradescrs is not None
- 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: %fs or %gs
- mc.MOV_rj(resloc.value, addr) # memory read
+ XXX
def get_set_errno(self, op, loc, issue_a_write):
# this function is only called on Linux
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,31 +693,9 @@
loc0 = self.xrm.force_result_in_reg(op.result, op.getarg(1))
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:
- resloc = self.force_allocate_reg(op.result)
- self.assembler.threadlocalref_get(op, resloc)
- 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 _consider_threadlocalref_addr(self, op):
+ resloc = self.force_allocate_reg(op.result)
+ self.assembler.threadlocalref_addr(resloc)
def _call(self, op, arglocs, force_store=[], guard_not_forced_op=None):
# we need to save registers on the stack:
@@ -796,12 +774,8 @@
return
if oopspecindex == EffectInfo.OS_MATH_SQRT:
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)
+ #if oopspecindex == EffectInfo.OS_THREADLOCALREF_ADDR:
+ # return self._consider_threadlocalref_addr(op)
if oopspecindex == EffectInfo.OS_MATH_READ_TIMESTAMP:
return self._consider_math_read_timestamp(op)
self._consider_call(op)
diff --git a/rpython/jit/backend/x86/stmtlocal.py
b/rpython/jit/backend/x86/stmtlocal.py
deleted file mode 100644
--- a/rpython/jit/backend/x86/stmtlocal.py
+++ /dev/null
@@ -1,43 +0,0 @@
-from rpython.rtyper.lltypesystem import lltype, rffi
-from rpython.translator.tool.cbuild import ExternalCompilationInfo
-from rpython.jit.backend.x86.arch import WORD
-
-SEGMENT_FS = '\x64'
-SEGMENT_GS = '\x65'
-
-if WORD == 4:
- SEGMENT_TL = SEGMENT_GS
- _instruction = "movl %%gs:0, %0"
-else:
- SEGMENT_TL = SEGMENT_FS
- _instruction = "movq %%fs:0, %0"
-
-eci = ExternalCompilationInfo(post_include_bits=['''
-#define RPY_STM_JIT 1
-static long pypy__threadlocal_base(void)
-{
- /* XXX ONLY LINUX WITH GCC/CLANG FOR NOW XXX */
- long result;
- asm("%s" : "=r"(result));
- return result;
-}
-static long pypy__get_errno_tl(void)
-{
- return ((long)&errno) - pypy__threadlocal_base();
-}
-''' % _instruction])
-
-
-threadlocal_base = rffi.llexternal(
- 'pypy__threadlocal_base',
- [], lltype.Signed,
- 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
@@ -22,9 +22,7 @@
OS_STR2UNICODE = 2 # "str.str2unicode"
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_THREADLOCALREF_ADDR = 5 # llop.threadlocalref_addr
OS_NOT_IN_TRACE = 8 # for calls not recorded in the jit
trace
#
OS_STR_CONCAT = 22 # "stroruni.concat"
diff --git a/rpython/jit/codewriter/jitcode.py
b/rpython/jit/codewriter/jitcode.py
--- a/rpython/jit/codewriter/jitcode.py
+++ b/rpython/jit/codewriter/jitcode.py
@@ -117,26 +117,6 @@
raise NotImplementedError
-class ThreadLocalRefDescr(AbstractDescr):
- # A special descr used as the extradescr in a call to a
- # threadlocalref_get function. If the backend supports it,
- # it can use this 'get_tlref_addr()' to get the address *in the
- # current thread* of the thread-local variable. If, on the current
- # platform, the "__thread" variables are implemented as an offset
- # from some base register (e.g. %fs on x86-64), then the backend will
- # immediately substract the current value of the base register.
- # This gives an offset from the base register, and this can be
- # written down in an assembler instruction to load the "__thread"
- # variable from anywhere.
-
- def __init__(self, opaque_id):
- from rpython.rtyper.lltypesystem.lloperation import llop
- from rpython.rtyper.lltypesystem import llmemory
- def get_tlref_addr():
- return llop.threadlocalref_getaddr(llmemory.Address, opaque_id)
- self.get_tlref_addr = get_tlref_addr
-
-
class LiveVarsInfo(object):
def __init__(self, live_i, live_r, live_f):
self.live_i = live_i
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
@@ -439,8 +439,6 @@
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:
@@ -1986,16 +1984,6 @@
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_ll_read_timestamp(self, op):
op1 = self.prepare_builtin_call(op, "ll_read_timestamp", [])
return self.handle_residual_call(op1,
@@ -2011,17 +1999,11 @@
None)
return [op0, op1]
- def rewrite_op_threadlocalref_get(self, op):
- from rpython.jit.codewriter.jitcode import ThreadLocalRefDescr
- opaqueid = op.args[0].value
- op1 = self.prepare_builtin_call(op, 'threadlocalref_getter', [],
- extra=(opaqueid,),
- extrakey=opaqueid._obj)
- extradescr = ThreadLocalRefDescr(opaqueid)
+ def rewrite_op_threadlocalref_addr(self, op):
+ op1 = self.prepare_builtin_call(op, 'threadlocalref_addr', [])
return self.handle_residual_call(op1,
- oopspecindex=EffectInfo.OS_THREADLOCALREF_GET,
- extraeffect=EffectInfo.EF_LOOPINVARIANT,
- extradescr=[extradescr])
+ oopspecindex=EffectInfo.OS_THREADLOCALREF_ADDR,
+ extraeffect=EffectInfo.EF_CANNOT_RAISE)
# ____________________________________________________________
diff --git a/rpython/jit/codewriter/support.py
b/rpython/jit/codewriter/support.py
--- a/rpython/jit/codewriter/support.py
+++ b/rpython/jit/codewriter/support.py
@@ -702,10 +702,8 @@
build_ll_1_raw_free_no_track_allocation = (
build_raw_free_builder(track_allocation=False))
- def build_ll_0_threadlocalref_getter(opaqueid):
- def _ll_0_threadlocalref_getter():
- return llop.threadlocalref_get(rclass.OBJECTPTR, opaqueid)
- return _ll_0_threadlocalref_getter
+ def _ll_0_threadlocalref_addr():
+ return llop.threadlocalref_addr(llmemory.Address)
def _ll_1_weakref_create(obj):
return llop.weakref_create(llmemory.WeakRefPtr, obj)
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,9 +148,7 @@
EI.OS_UNIEQ_LENGTHOK: ([PUNICODE, PUNICODE], INT),
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),
+ EI.OS_THREADLOCALREF_ADDR: ([], llmemory.Address),
}
argtypes = argtypes[oopspecindex]
assert argtypes[0] == [v.concretetype for v in op.args[1:]]
@@ -160,11 +158,8 @@
elif oopspecindex == EI.OS_RAW_MALLOC_VARSIZE_CHAR:
assert extraeffect == EI.EF_CAN_RAISE
elif oopspecindex in (EI.OS_RAW_FREE,
- EI.OS_GET_ERRNO,
- EI.OS_SET_ERRNO):
+ EI.OS_THREADLOCALREF_ADDR):
assert extraeffect == EI.EF_CANNOT_RAISE
- elif oopspecindex == EI.OS_THREADLOCALREF_GET:
- assert extraeffect == EI.EF_LOOPINVARIANT
else:
assert extraeffect == EI.EF_ELIDABLE_CANNOT_RAISE
return 'calldescr-%d' % oopspecindex
@@ -1346,54 +1341,17 @@
assert op1.result is None
assert op2 is None
-def test_threadlocalref_get():
- from rpython.rtyper import rclass
- from rpython.rlib.rthread import ThreadLocalReference
- OS_THREADLOCALREF_GET = effectinfo.EffectInfo.OS_THREADLOCALREF_GET
- class Foo: pass
- t = ThreadLocalReference(Foo)
- v2 = varoftype(rclass.OBJECTPTR)
- c_opaqueid = const(t.opaque_id)
- op = SpaceOperation('threadlocalref_get', [c_opaqueid], v2)
+def test_threadlocalref_addr():
+ OS_THREADLOCALREF_ADDR = effectinfo.EffectInfo.OS_THREADLOCALREF_ADDR
+ v = varoftype(llmemory.Address)
+ op = SpaceOperation('threadlocalref_addr', [], v)
tr = Transformer(FakeCPU(), FakeBuiltinCallControl())
op0 = tr.rewrite_operation(op)
- assert op0.opname == 'residual_call_r_r'
- assert op0.args[0].value == 'threadlocalref_getter' # pseudo-function as
str
+ assert op0.opname == 'residual_call_r_i'
+ assert op0.args[0].value == 'threadlocalref_addr' # pseudo-function as str
assert op0.args[1] == ListOfKind("ref", [])
- 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
+ assert op0.args[2] == 'calldescr-%d' % OS_THREADLOCALREF_ADDR
+ assert op0.result == v
def test_unknown_operation():
op = SpaceOperation('foobar', [], varoftype(lltype.Void))
diff --git a/rpython/jit/metainterp/test/test_threadlocal.py
b/rpython/jit/metainterp/test/test_threadlocal.py
--- a/rpython/jit/metainterp/test/test_threadlocal.py
+++ b/rpython/jit/metainterp/test/test_threadlocal.py
@@ -1,29 +1,19 @@
import py
from rpython.jit.metainterp.test.support import LLJitMixin
-from rpython.rlib.rthread import ThreadLocalReference
-from rpython.rlib.jit import dont_look_inside
+from rpython.rtyper.lltypesystem import llmemory
+from rpython.rtyper.lltypesystem.lloperation import llop
class ThreadLocalTest(object):
def test_threadlocalref_get(self):
- class Foo:
- pass
- t = ThreadLocalReference(Foo)
- x = Foo()
-
- @dont_look_inside
- def setup():
- t.set(x)
-
def f():
- setup()
- if t.get() is x:
- return 42
- return -666
+ addr1 = llop.threadlocalref_addr(llmemory.Address)
+ # a "does not crash" test only
+ return 1
res = self.interp_operations(f, [])
- assert res == 42
+ assert res == 1
class TestLLtype(ThreadLocalTest, LLJitMixin):
diff --git a/rpython/rlib/rthread.py b/rpython/rlib/rthread.py
--- a/rpython/rlib/rthread.py
+++ b/rpython/rlib/rthread.py
@@ -284,17 +284,17 @@
def getraw():
_threadlocalref_seeme(self)
- addr = llop.threadlocalref_addr(rffi.CCHARP)
+ addr = llop.threadlocalref_addr(llmemory.Address)
return llop.raw_load(FIELDTYPE, addr, offset)
def get_or_make_raw():
_threadlocalref_seeme(self)
- addr = llop.threadlocalref_make(rffi.CCHARP)
+ addr = llop.threadlocalref_make(llmemory.Address)
return llop.raw_load(FIELDTYPE, addr, offset)
def setraw(value):
_threadlocalref_seeme(self)
- addr = llop.threadlocalref_addr(rffi.CCHARP)
+ addr = llop.threadlocalref_addr(llmemory.Address)
llop.raw_store(lltype.Void, addr, offset, value)
self.getraw = getraw
@@ -315,14 +315,16 @@
self.local = thread._local() # <- NOT_RPYTHON
unique_id = ThreadLocalReference._COUNT
ThreadLocalReference._COUNT += 1
- ThreadLocalField.__init__(self, llmemory.GCREF, 'tlref%d' % unique_id)
+ ThreadLocalField.__init__(self, lltype.Signed, 'tlref%d' % unique_id)
getraw = self.getraw
setraw = self.setraw
def get():
if we_are_translated():
from rpython.rtyper.annlowlevel import cast_gcref_to_instance
- return cast_gcref_to_instance(Cls, getraw())
+ value = getraw()
+ value = lltype.cast_int_to_ptr(llmemory.GCREF, value)
+ return cast_gcref_to_instance(Cls, value)
else:
return getattr(self.local, 'value', None)
@@ -337,7 +339,8 @@
if not running_on_llinterp:
if gcref:
_make_sure_does_not_move(gcref)
- setraw(gcref)
+ value = lltype.cast_ptr_to_int(gcref)
+ setraw(value)
else:
self.local.value = value
diff --git a/rpython/rtyper/llinterp.py b/rpython/rtyper/llinterp.py
--- a/rpython/rtyper/llinterp.py
+++ b/rpython/rtyper/llinterp.py
@@ -919,8 +919,16 @@
def op_stack_current(self):
return 0
- def op_threadlocalref_addr(self, key, value):
+ def op_threadlocalref_addr(self):
raise NotImplementedError("threadlocalref_addr")
+ ## class FakeThreadLocalAddr(object):
+ ## is_fake_thread_local_addr = True
+ ## _TYPE = llmemory.Address
+ ## def _cast_to_int(self, symbolic=None):
+ ## return FakeThreadLocalAddrAsInt()
+ ## class FakeThreadLocalAddrAsInt(object):
+ ## _TYPE = lltype.Signed
+ ## return FakeThreadLocalAddr()
# __________________________________________________________
# operations on addresses
@@ -967,6 +975,9 @@
ll_p = rffi.cast(rffi.CArrayPtr(RESTYPE),
rffi.ptradd(ll_p, offset))
value = ll_p[0]
+ ## elif getattr(addr, 'is_fake_thread_local_addr', False):
+ ## assert type(offset) is CDefinedIntSymbolic
+ ## value = self.llinterpreter.tlobj[offset.expr]
else:
assert offset.TYPE == RESTYPE
value = getattr(addr, str(RESTYPE).lower())[offset.repeat]
@@ -987,6 +998,9 @@
ll_p = rffi.cast(rffi.CArrayPtr(ARGTYPE),
rffi.ptradd(ll_p, offset))
ll_p[0] = value
+ ## elif getattr(addr, 'is_fake_thread_local_addr', False):
+ ## assert type(offset) is CDefinedIntSymbolic
+ ## self.llinterpreter.tlobj[offset.expr] = value
else:
assert offset.TYPE == ARGTYPE
getattr(addr, str(ARGTYPE).lower())[offset.repeat] = value
diff --git a/rpython/rtyper/lltypesystem/test/test_llmemory.py
b/rpython/rtyper/lltypesystem/test/test_llmemory.py
--- a/rpython/rtyper/lltypesystem/test/test_llmemory.py
+++ b/rpython/rtyper/lltypesystem/test/test_llmemory.py
@@ -649,3 +649,13 @@
#assert cast_int_to_adr(i) == adr -- depends on ll2ctypes details
i = cast_adr_to_int(NULL, mode="forced")
assert is_valid_int(i) and i == 0
+
+def test_cast_gcref_to_int():
+ A = lltype.GcArray(Address)
+ def f():
+ ptr = lltype.malloc(A, 10)
+ gcref = lltype.cast_opaque_ptr(GCREF, ptr)
+ adr = lltype.cast_ptr_to_int(gcref)
+ assert adr == lltype.cast_ptr_to_int(ptr)
+ f()
+ interpret(f, [])
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit