[pypy-commit] pypy alt_errno: merge default into branch
mattip
noreply at buildbot.pypy.org
Thu Feb 19 09:06:02 CET 2015
Author: mattip <matti.picus at gmail.com>
Branch: alt_errno
Changeset: r75991:c99027ae4f08
Date: 2015-02-19 10:01 +0200
http://bitbucket.org/pypy/pypy/changeset/c99027ae4f08/
Log: merge default into branch
diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst
--- a/pypy/doc/whatsnew-head.rst
+++ b/pypy/doc/whatsnew-head.rst
@@ -23,3 +23,6 @@
Fix exception being raised by kqueue.control (CPython compatibility)
.. branch: gitignore
+
+.. branch: framestate2
+Refactor rpython.flowspace.framestate.FrameState.
diff --git a/pypy/module/_ssl/test/test_ssl.py b/pypy/module/_ssl/test/test_ssl.py
--- a/pypy/module/_ssl/test/test_ssl.py
+++ b/pypy/module/_ssl/test/test_ssl.py
@@ -236,6 +236,9 @@
def test_npn_protocol(self):
import socket, _ssl, gc
+ if not _ssl.HAS_NPN:
+ skip("NPN requires OpenSSL 1.0.1 or greater")
+
ctx = _ssl._SSLContext(_ssl.PROTOCOL_TLSv1)
ctx._set_npn_protocols(b'\x08http/1.1\x06spdy/2')
ss = ctx._wrap_socket(self.s._sock, True,
diff --git a/pypy/objspace/std/intobject.py b/pypy/objspace/std/intobject.py
--- a/pypy/objspace/std/intobject.py
+++ b/pypy/objspace/std/intobject.py
@@ -427,9 +427,11 @@
def descr_bit_length(self, space):
val = self.intval
+ bits = 0
if val < 0:
- val = -val
- bits = 0
+ # warning, "-val" overflows here
+ val = -((val + 1) >> 1)
+ bits = 1
while val:
bits += 1
val >>= 1
diff --git a/pypy/objspace/std/test/test_intobject.py b/pypy/objspace/std/test/test_intobject.py
--- a/pypy/objspace/std/test/test_intobject.py
+++ b/pypy/objspace/std/test/test_intobject.py
@@ -521,11 +521,20 @@
(10, 4),
(150, 8),
(-1, 1),
+ (-2, 2),
+ (-3, 2),
+ (-4, 3),
(-10, 4),
(-150, 8),
]:
assert val.bit_length() == bits
+ def test_bit_length_max(self):
+ import sys
+ val = -sys.maxint-1
+ bits = 32 if val == -2147483648 else 64
+ assert val.bit_length() == bits
+
def test_int_real(self):
class A(int): pass
b = A(5).real
diff --git a/rpython/flowspace/flowcontext.py b/rpython/flowspace/flowcontext.py
--- a/rpython/flowspace/flowcontext.py
+++ b/rpython/flowspace/flowcontext.py
@@ -12,8 +12,7 @@
from rpython.flowspace.argument import CallSpec
from rpython.flowspace.model import (Constant, Variable, Block, Link,
c_last_exception, const, FSException)
-from rpython.flowspace.framestate import (FrameState, recursively_unflatten,
- recursively_flatten)
+from rpython.flowspace.framestate import FrameState
from rpython.flowspace.specialcase import (rpython_print_item,
rpython_print_newline)
from rpython.flowspace.operation import op
@@ -278,6 +277,7 @@
"cmp_exc_match",
]
+
class FlowContext(object):
def __init__(self, graph, code):
self.graph = graph
@@ -307,112 +307,91 @@
The locals are ordered according to self.pycode.signature.
"""
- self.valuestackdepth = code.co_nlocals
- self.locals_stack_w = [None] * (code.co_stacksize + code.co_nlocals)
+ self.nlocals = code.co_nlocals
+ self.locals_w = [None] * code.co_nlocals
+ self.stack = []
+
+ @property
+ def stackdepth(self):
+ return len(self.stack)
def pushvalue(self, w_object):
- depth = self.valuestackdepth
- self.locals_stack_w[depth] = w_object
- self.valuestackdepth = depth + 1
+ self.stack.append(w_object)
def popvalue(self):
- depth = self.valuestackdepth - 1
- assert depth >= self.pycode.co_nlocals, "pop from empty value stack"
- w_object = self.locals_stack_w[depth]
- self.locals_stack_w[depth] = None
- self.valuestackdepth = depth
- return w_object
+ return self.stack.pop()
def peekvalue(self, index_from_top=0):
# NOTE: top of the stack is peekvalue(0).
- index = self.valuestackdepth + ~index_from_top
- assert index >= self.pycode.co_nlocals, (
- "peek past the bottom of the stack")
- return self.locals_stack_w[index]
+ index = ~index_from_top
+ return self.stack[index]
def settopvalue(self, w_object, index_from_top=0):
- index = self.valuestackdepth + ~index_from_top
- assert index >= self.pycode.co_nlocals, (
- "settop past the bottom of the stack")
- self.locals_stack_w[index] = w_object
+ index = ~index_from_top
+ self.stack[index] = w_object
def popvalues(self, n):
- values_w = [self.popvalue() for i in range(n)]
- values_w.reverse()
+ if n == 0:
+ return []
+ values_w = self.stack[-n:]
+ del self.stack[-n:]
return values_w
- def dropvalues(self, n):
- finaldepth = self.valuestackdepth - n
- for n in range(finaldepth, self.valuestackdepth):
- self.locals_stack_w[n] = None
- self.valuestackdepth = finaldepth
-
def dropvaluesuntil(self, finaldepth):
- for n in range(finaldepth, self.valuestackdepth):
- self.locals_stack_w[n] = None
- self.valuestackdepth = finaldepth
-
- def save_locals_stack(self):
- return self.locals_stack_w[:self.valuestackdepth]
-
- def restore_locals_stack(self, items_w):
- self.locals_stack_w[:len(items_w)] = items_w
- self.dropvaluesuntil(len(items_w))
+ del self.stack[finaldepth:]
def getstate(self, next_offset):
- # getfastscope() can return real None, for undefined locals
- data = self.save_locals_stack()
- if self.last_exception is None:
- data.append(Constant(None))
- data.append(Constant(None))
- else:
- data.append(self.last_exception.w_type)
- data.append(self.last_exception.w_value)
- recursively_flatten(data)
- return FrameState(data, self.blockstack[:], next_offset)
+ return FrameState(self.locals_w[:], self.stack[:],
+ self.last_exception, self.blockstack[:], next_offset)
def setstate(self, state):
""" Reset the context to the given frame state. """
- data = state.mergeable[:]
- recursively_unflatten(data)
- self.restore_locals_stack(data[:-2]) # Nones == undefined locals
- if data[-2] == Constant(None):
- assert data[-1] == Constant(None)
- self.last_exception = None
- else:
- self.last_exception = FSException(data[-2], data[-1])
+ self.locals_w = state.locals_w[:]
+ self.stack = state.stack[:]
+ self.last_exception = state.last_exception
self.blockstack = state.blocklist[:]
+ self._normalize_raise_signals()
+
+ def _normalize_raise_signals(self):
+ st = self.stack
+ for i in range(len(st)):
+ if isinstance(st[i], RaiseImplicit):
+ st[i] = Raise(st[i].w_exc)
def guessbool(self, w_condition):
if isinstance(w_condition, Constant):
return w_condition.value
return self.recorder.guessbool(self, w_condition)
- def record(self, spaceop):
+ def maybe_merge(self):
recorder = self.recorder
if getattr(recorder, 'final_state', None) is not None:
self.mergeblock(recorder.crnt_block, recorder.final_state)
raise StopFlowing
+
+ def record(self, spaceop):
spaceop.offset = self.last_offset
- recorder.append(spaceop)
+ self.recorder.append(spaceop)
def do_op(self, op):
+ self.maybe_merge()
self.record(op)
self.guessexception(op.canraise)
return op.result
- def guessexception(self, exceptions, force=False):
+ def guessexception(self, exceptions):
"""
Catch possible exceptions implicitly.
"""
if not exceptions:
return
- if not force and not any(isinstance(block, (ExceptBlock, FinallyBlock))
- for block in self.blockstack):
- # The implicit exception wouldn't be caught and would later get
- # removed, so don't bother creating it.
- return
- self.recorder.guessexception(self, *exceptions)
+ # Implicit exceptions are ignored unless they are caught explicitly
+ if self.has_exc_handler():
+ self.recorder.guessexception(self, *exceptions)
+
+ def has_exc_handler(self):
+ return any(isinstance(block, (ExceptBlock, FinallyBlock))
+ for block in self.blockstack)
def build_flow(self):
graph = self.graph
@@ -430,35 +409,8 @@
while True:
next_offset = self.handle_bytecode(next_offset)
self.recorder.final_state = self.getstate(next_offset)
-
- except RaiseImplicit as e:
- w_exc = e.w_exc
- if isinstance(w_exc.w_type, Constant):
- exc_cls = w_exc.w_type.value
- else:
- exc_cls = Exception
- msg = "implicit %s shouldn't occur" % exc_cls.__name__
- w_type = Constant(AssertionError)
- w_value = Constant(AssertionError(msg))
- link = Link([w_type, w_value], self.graph.exceptblock)
- self.recorder.crnt_block.closeblock(link)
-
- except Raise as e:
- w_exc = e.w_exc
- if w_exc.w_type == const(ImportError):
- msg = 'import statement always raises %s' % e
- raise ImportError(msg)
- link = Link([w_exc.w_type, w_exc.w_value], self.graph.exceptblock)
- self.recorder.crnt_block.closeblock(link)
-
except StopFlowing:
pass
-
- except Return as exc:
- w_result = exc.w_value
- link = Link([w_result], self.graph.returnblock)
- self.recorder.crnt_block.closeblock(link)
-
except FlowingError as exc:
if exc.ctx is None:
exc.ctx = self
@@ -476,14 +428,8 @@
if newstate is not None:
break
else:
- newstate = currentstate.copy()
- newblock = SpamBlock(newstate)
- # unconditionally link the current block to the newblock
- outputargs = currentstate.getoutputargs(newstate)
- link = Link(outputargs, newblock)
- currentblock.closeblock(link)
+ newblock = self.make_next_block(currentblock, currentstate)
candidates.insert(0, newblock)
- self.pendingblocks.append(newblock)
return
if newstate.matches(block.framestate):
@@ -493,7 +439,7 @@
newblock = SpamBlock(newstate)
varnames = self.pycode.co_varnames
- for name, w_value in zip(varnames, newstate.mergeable):
+ for name, w_value in zip(varnames, newstate.locals_w):
if isinstance(w_value, Variable):
w_value.rename(name)
# unconditionally link the current block to the newblock
@@ -513,11 +459,21 @@
candidates.insert(0, newblock)
self.pendingblocks.append(newblock)
+ def make_next_block(self, block, state):
+ newstate = state.copy()
+ newblock = SpamBlock(newstate)
+ # unconditionally link the current block to the newblock
+ outputargs = state.getoutputargs(newstate)
+ link = Link(outputargs, newblock)
+ block.closeblock(link)
+ self.pendingblocks.append(newblock)
+ return newblock
+
# hack for unrolling iterables, don't use this
def replace_in_stack(self, oldvalue, newvalue):
w_new = Constant(newvalue)
- stack_items_w = self.locals_stack_w
- for i in range(self.valuestackdepth - 1, self.pycode.co_nlocals - 1, -1):
+ stack_items_w = self.stack
+ for i in range(self.stackdepth - 1, - 1, -1):
w_v = stack_items_w[i]
if isinstance(w_v, Constant):
if w_v.value is oldvalue:
@@ -541,7 +497,7 @@
if isinstance(signal, block.handles):
return block.handle(self, signal)
block.cleanupstack(self)
- return signal.nomoreblocks()
+ return signal.nomoreblocks(self)
def getlocalvarname(self, index):
return self.pycode.co_varnames[index]
@@ -870,7 +826,7 @@
op.simple_call(w_exitfunc, w_None, w_None, w_None).eval(self)
def LOAD_FAST(self, varindex):
- w_value = self.locals_stack_w[varindex]
+ w_value = self.locals_w[varindex]
if w_value is None:
raise FlowingError("Local variable referenced before assignment")
self.pushvalue(w_value)
@@ -915,7 +871,7 @@
def STORE_FAST(self, varindex):
w_newvalue = self.popvalue()
assert w_newvalue is not None
- self.locals_stack_w[varindex] = w_newvalue
+ self.locals_w[varindex] = w_newvalue
if isinstance(w_newvalue, Variable):
w_newvalue.rename(self.getlocalvarname(varindex))
@@ -1128,11 +1084,11 @@
op.simple_call(w_append_meth, w_value).eval(self)
def DELETE_FAST(self, varindex):
- if self.locals_stack_w[varindex] is None:
+ if self.locals_w[varindex] is None:
varname = self.getlocalvarname(varindex)
message = "local variable '%s' referenced before assignment"
raise UnboundLocalError(message, varname)
- self.locals_stack_w[varindex] = None
+ self.locals_w[varindex] = None
def STORE_MAP(self, oparg):
w_key = self.popvalue()
@@ -1220,25 +1176,32 @@
WHY_CONTINUE, Continue
WHY_YIELD not needed
"""
- def nomoreblocks(self):
+ def nomoreblocks(self, ctx):
raise BytecodeCorruption("misplaced bytecode - should not return")
+ def __eq__(self, other):
+ return type(other) is type(self) and other.args == self.args
+
class Return(FlowSignal):
"""Signals a 'return' statement.
- Argument is the wrapped object to return."""
-
+ Argument is the wrapped object to return.
+ """
def __init__(self, w_value):
self.w_value = w_value
- def nomoreblocks(self):
- raise Return(self.w_value)
+ def nomoreblocks(self, ctx):
+ w_result = self.w_value
+ link = Link([w_result], ctx.graph.returnblock)
+ ctx.recorder.crnt_block.closeblock(link)
+ raise StopFlowing
- def state_unpack_variables(self):
+ @property
+ def args(self):
return [self.w_value]
@staticmethod
- def state_pack_variables(w_value):
+ def rebuild(w_value):
return Return(w_value)
class Raise(FlowSignal):
@@ -1248,28 +1211,48 @@
def __init__(self, w_exc):
self.w_exc = w_exc
- def nomoreblocks(self):
- raise self
+ def nomoreblocks(self, ctx):
+ w_exc = self.w_exc
+ if w_exc.w_type == const(ImportError):
+ msg = 'import statement always raises %s' % self
+ raise ImportError(msg)
+ link = Link([w_exc.w_type, w_exc.w_value], ctx.graph.exceptblock)
+ ctx.recorder.crnt_block.closeblock(link)
+ raise StopFlowing
- def state_unpack_variables(self):
+ @property
+ def args(self):
return [self.w_exc.w_type, self.w_exc.w_value]
- @staticmethod
- def state_pack_variables(w_type, w_value):
- return Raise(FSException(w_type, w_value))
+ @classmethod
+ def rebuild(cls, w_type, w_value):
+ return cls(FSException(w_type, w_value))
class RaiseImplicit(Raise):
"""Signals an exception raised implicitly"""
+ def nomoreblocks(self, ctx):
+ w_exc = self.w_exc
+ if isinstance(w_exc.w_type, Constant):
+ exc_cls = w_exc.w_type.value
+ else:
+ exc_cls = Exception
+ msg = "implicit %s shouldn't occur" % exc_cls.__name__
+ w_type = Constant(AssertionError)
+ w_value = Constant(AssertionError(msg))
+ link = Link([w_type, w_value], ctx.graph.exceptblock)
+ ctx.recorder.crnt_block.closeblock(link)
+ raise StopFlowing
class Break(FlowSignal):
"""Signals a 'break' statement."""
- def state_unpack_variables(self):
+ @property
+ def args(self):
return []
@staticmethod
- def state_pack_variables():
+ def rebuild():
return Break.singleton
Break.singleton = Break()
@@ -1281,11 +1264,12 @@
def __init__(self, jump_to):
self.jump_to = jump_to
- def state_unpack_variables(self):
+ @property
+ def args(self):
return [const(self.jump_to)]
@staticmethod
- def state_pack_variables(w_jump_to):
+ def rebuild(w_jump_to):
return Continue(w_jump_to.value)
@@ -1295,21 +1279,21 @@
def __init__(self, ctx, handlerposition):
self.handlerposition = handlerposition
- self.valuestackdepth = ctx.valuestackdepth
+ self.stackdepth = ctx.stackdepth
def __eq__(self, other):
return (self.__class__ is other.__class__ and
self.handlerposition == other.handlerposition and
- self.valuestackdepth == other.valuestackdepth)
+ self.stackdepth == other.stackdepth)
def __ne__(self, other):
return not (self == other)
def __hash__(self):
- return hash((self.handlerposition, self.valuestackdepth))
+ return hash((self.handlerposition, self.stackdepth))
def cleanupstack(self, ctx):
- ctx.dropvaluesuntil(self.valuestackdepth)
+ ctx.dropvaluesuntil(self.stackdepth)
def handle(self, ctx, unroller):
raise NotImplementedError
diff --git a/rpython/flowspace/framestate.py b/rpython/flowspace/framestate.py
--- a/rpython/flowspace/framestate.py
+++ b/rpython/flowspace/framestate.py
@@ -1,21 +1,50 @@
-from rpython.flowspace.model import Variable, Constant
+from rpython.flowspace.model import Variable, Constant, FSException
from rpython.rlib.unroll import SpecTag
+def _copy(v):
+ from rpython.flowspace.flowcontext import FlowSignal
+ if isinstance(v, Variable):
+ return Variable(v)
+ elif isinstance(v, FlowSignal):
+ vars = [_copy(var) for var in v.args]
+ return v.rebuild(*vars)
+ else:
+ return v
+
+def _union(seq1, seq2):
+ return [union(v1, v2) for v1, v2 in zip(seq1, seq2)]
+
class FrameState(object):
- def __init__(self, mergeable, blocklist, next_offset):
- self.mergeable = mergeable
+ def __init__(self, locals_w, stack, last_exception, blocklist, next_offset):
+ self.locals_w = locals_w
+ self.stack = stack
+ self.last_exception = last_exception
self.blocklist = blocklist
self.next_offset = next_offset
+ self._mergeable = None
+
+ @property
+ def mergeable(self):
+ if self._mergeable is not None:
+ return self._mergeable
+ self._mergeable = data = self.locals_w + self.stack
+ if self.last_exception is None:
+ data.append(Constant(None))
+ data.append(Constant(None))
+ else:
+ data.append(self.last_exception.w_type)
+ data.append(self.last_exception.w_value)
+ recursively_flatten(data)
+ return data
def copy(self):
"Make a copy of this state in which all Variables are fresh."
- newstate = []
- for w in self.mergeable:
- if isinstance(w, Variable):
- w = Variable(w)
- newstate.append(w)
- return FrameState(newstate, self.blocklist, self.next_offset)
+ exc = self.last_exception
+ if exc is not None:
+ exc = FSException(_copy(exc.w_type), _copy(exc.w_value))
+ return FrameState(map(_copy, self.locals_w), map(_copy, self.stack),
+ exc, self.blocklist, self.next_offset)
def getvariables(self):
return [w for w in self.mergeable if isinstance(w, Variable)]
@@ -33,18 +62,31 @@
return False
return True
+ def _exc_args(self):
+ if self.last_exception is None:
+ return [Constant(None), Constant(None)]
+ else:
+ return [self.last_exception.w_type,
+ self.last_exception.w_value]
+
def union(self, other):
"""Compute a state that is at least as general as both self and other.
A state 'a' is more general than a state 'b' if all Variables in 'b'
are also Variables in 'a', but 'a' may have more Variables.
"""
- newstate = []
try:
- for w1, w2 in zip(self.mergeable, other.mergeable):
- newstate.append(union(w1, w2))
+ locals = _union(self.locals_w, other.locals_w)
+ stack = _union(self.stack, other.stack)
+ if self.last_exception is None and other.last_exception is None:
+ exc = None
+ else:
+ args1 = self._exc_args()
+ args2 = other._exc_args()
+ exc = FSException(union(args1[0], args2[0]),
+ union(args1[1], args2[1]))
except UnionError:
return None
- return FrameState(newstate, self.blocklist, self.next_offset)
+ return FrameState(locals, stack, exc, self.blocklist, self.next_offset)
def getoutputargs(self, targetstate):
"Return the output arguments needed to link self to targetstate."
@@ -61,6 +103,7 @@
def union(w1, w2):
"Union of two variables or constants."
+ from rpython.flowspace.flowcontext import FlowSignal
if w1 == w2:
return w1
if w1 is None or w2 is None:
@@ -69,38 +112,21 @@
if isinstance(w1, Variable) or isinstance(w2, Variable):
return Variable() # new fresh Variable
if isinstance(w1, Constant) and isinstance(w2, Constant):
- # FlowSignal represent stack unrollers in the stack.
- # They should not be merged because they will be unwrapped.
- # This is needed for try:except: and try:finally:, though
- # it makes the control flow a bit larger by duplicating the
- # handlers.
- dont_merge_w1 = w1 in UNPICKLE_TAGS or isinstance(w1.value, SpecTag)
- dont_merge_w2 = w2 in UNPICKLE_TAGS or isinstance(w2.value, SpecTag)
- if dont_merge_w1 or dont_merge_w2:
+ if isinstance(w1.value, SpecTag) or isinstance(w2.value, SpecTag):
raise UnionError
else:
return Variable() # generalize different constants
+ if isinstance(w1, FlowSignal) and isinstance(w2, FlowSignal):
+ if type(w1) is not type(w2):
+ raise UnionError
+ vars = [union(v1, v2) for v1, v2 in zip(w1.args, w2.args)]
+ return w1.rebuild(*vars)
+ if isinstance(w1, FlowSignal) or isinstance(w2, FlowSignal):
+ raise UnionError
raise TypeError('union of %r and %r' % (w1.__class__.__name__,
w2.__class__.__name__))
-# ____________________________________________________________
-#
-# We have to flatten out the state of the frame into a list of
-# Variables and Constants. This is done above by collecting the
-# locals and the items on the value stack, but the latter may contain
-# FlowSignal. We have to handle these specially, because
-# some of them hide references to more Variables and Constants.
-# The trick is to flatten ("pickle") them into the list so that the
-# extra Variables show up directly in the list too.
-
-class PickleTag:
- pass
-
-PICKLE_TAGS = {}
-UNPICKLE_TAGS = {}
-
-
def recursively_flatten(lst):
from rpython.flowspace.flowcontext import FlowSignal
i = 0
@@ -109,22 +135,4 @@
if not isinstance(unroller, FlowSignal):
i += 1
else:
- vars = unroller.state_unpack_variables()
- key = unroller.__class__, len(vars)
- try:
- tag = PICKLE_TAGS[key]
- except KeyError:
- tag = PICKLE_TAGS[key] = Constant(PickleTag())
- UNPICKLE_TAGS[tag] = key
- lst[i:i + 1] = [tag] + vars
-
-
-def recursively_unflatten(lst):
- for i in xrange(len(lst) - 1, -1, -1):
- item = lst[i]
- if item in UNPICKLE_TAGS:
- unrollerclass, argcount = UNPICKLE_TAGS[item]
- arguments = lst[i + 1:i + 1 + argcount]
- del lst[i + 1:i + 1 + argcount]
- unroller = unrollerclass.state_pack_variables(*arguments)
- lst[i] = unroller
+ lst[i:i + 1] = unroller.args
diff --git a/rpython/flowspace/operation.py b/rpython/flowspace/operation.py
--- a/rpython/flowspace/operation.py
+++ b/rpython/flowspace/operation.py
@@ -517,7 +517,7 @@
ctx.replace_in_stack(it, next_unroller)
return const(v)
w_item = ctx.do_op(self)
- ctx.guessexception([StopIteration, RuntimeError], force=True)
+ ctx.recorder.guessexception(ctx, StopIteration, RuntimeError)
return w_item
class GetAttr(SingleDispatchMixin, HLOperation):
diff --git a/rpython/flowspace/pygraph.py b/rpython/flowspace/pygraph.py
--- a/rpython/flowspace/pygraph.py
+++ b/rpython/flowspace/pygraph.py
@@ -11,10 +11,10 @@
def __init__(self, func, code):
from rpython.flowspace.flowcontext import SpamBlock
- data = [None] * code.co_nlocals
+ locals = [None] * code.co_nlocals
for i in range(code.formalargcount):
- data[i] = Variable(code.co_varnames[i])
- state = FrameState(data + [Constant(None), Constant(None)], [], 0)
+ locals[i] = Variable(code.co_varnames[i])
+ state = FrameState(locals, [], None, [], 0)
initialblock = SpamBlock(state)
super(PyGraph, self).__init__(self._sanitize_funcname(func), initialblock)
self.func = func
diff --git a/rpython/flowspace/test/test_flowcontext.py b/rpython/flowspace/test/test_flowcontext.py
new file mode 100644
--- /dev/null
+++ b/rpython/flowspace/test/test_flowcontext.py
@@ -0,0 +1,15 @@
+""" Unit tests for flowcontext.py """
+import pytest
+from rpython.flowspace.model import Variable, FSException
+from rpython.flowspace.flowcontext import (
+ Return, Raise, RaiseImplicit, Continue, Break)
+
+ at pytest.mark.parametrize('signal', [
+ Return(Variable()),
+ Raise(FSException(Variable(), Variable())),
+ RaiseImplicit(FSException(Variable(), Variable())),
+ Break(),
+ Continue(42),
+])
+def test_signals(signal):
+ assert signal.rebuild(*signal.args) == signal
diff --git a/rpython/flowspace/test/test_framestate.py b/rpython/flowspace/test/test_framestate.py
--- a/rpython/flowspace/test/test_framestate.py
+++ b/rpython/flowspace/test/test_framestate.py
@@ -15,7 +15,7 @@
ctx = FlowContext(graph, code)
# hack the frame
ctx.setstate(graph.startblock.framestate)
- ctx.locals_stack_w[ctx.pycode.co_nlocals-1] = Constant(None)
+ ctx.locals_w[-1] = Constant(None)
return ctx
def func_simple(x):
@@ -31,7 +31,7 @@
def test_neq_hacked_framestate(self):
ctx = self.get_context(self.func_simple)
fs1 = ctx.getstate(0)
- ctx.locals_stack_w[ctx.pycode.co_nlocals-1] = Variable()
+ ctx.locals_w[-1] = Variable()
fs2 = ctx.getstate(0)
assert not fs1.matches(fs2)
@@ -44,7 +44,7 @@
def test_union_on_hacked_framestates(self):
ctx = self.get_context(self.func_simple)
fs1 = ctx.getstate(0)
- ctx.locals_stack_w[ctx.pycode.co_nlocals-1] = Variable()
+ ctx.locals_w[-1] = Variable()
fs2 = ctx.getstate(0)
assert fs1.union(fs2).matches(fs2) # fs2 is more general
assert fs2.union(fs1).matches(fs2) # fs2 is more general
@@ -52,7 +52,7 @@
def test_restore_frame(self):
ctx = self.get_context(self.func_simple)
fs1 = ctx.getstate(0)
- ctx.locals_stack_w[ctx.pycode.co_nlocals-1] = Variable()
+ ctx.locals_w[-1] = Variable()
ctx.setstate(fs1)
assert fs1.matches(ctx.getstate(0))
@@ -71,26 +71,25 @@
def test_getoutputargs(self):
ctx = self.get_context(self.func_simple)
fs1 = ctx.getstate(0)
- ctx.locals_stack_w[ctx.pycode.co_nlocals-1] = Variable()
+ ctx.locals_w[-1] = Variable()
fs2 = ctx.getstate(0)
outputargs = fs1.getoutputargs(fs2)
# 'x' -> 'x' is a Variable
# locals_w[n-1] -> locals_w[n-1] is Constant(None)
- assert outputargs == [ctx.locals_stack_w[0], Constant(None)]
+ assert outputargs == [ctx.locals_w[0], Constant(None)]
def test_union_different_constants(self):
ctx = self.get_context(self.func_simple)
fs1 = ctx.getstate(0)
- ctx.locals_stack_w[ctx.pycode.co_nlocals-1] = Constant(42)
+ ctx.locals_w[-1] = Constant(42)
fs2 = ctx.getstate(0)
fs3 = fs1.union(fs2)
ctx.setstate(fs3)
- assert isinstance(ctx.locals_stack_w[ctx.pycode.co_nlocals-1],
- Variable) # generalized
+ assert isinstance(ctx.locals_w[-1], Variable) # generalized
def test_union_spectag(self):
ctx = self.get_context(self.func_simple)
fs1 = ctx.getstate(0)
- ctx.locals_stack_w[ctx.pycode.co_nlocals-1] = Constant(SpecTag())
+ ctx.locals_w[-1] = Constant(SpecTag())
fs2 = ctx.getstate(0)
assert fs1.union(fs2) is None # UnionError
diff --git a/rpython/jit/metainterp/compile.py b/rpython/jit/metainterp/compile.py
--- a/rpython/jit/metainterp/compile.py
+++ b/rpython/jit/metainterp/compile.py
@@ -749,18 +749,14 @@
rstack._stack_criticalcode_stop()
def handle_async_forcing(self, deadframe):
- from rpython.jit.metainterp.resume import (force_from_resumedata,
- AlreadyForced)
+ from rpython.jit.metainterp.resume import force_from_resumedata
metainterp_sd = self.metainterp_sd
vinfo = self.jitdriver_sd.virtualizable_info
ginfo = self.jitdriver_sd.greenfield_info
# there is some chance that this is already forced. In this case
# the virtualizable would have a token = NULL
- try:
- all_virtuals = force_from_resumedata(metainterp_sd, self, deadframe,
- vinfo, ginfo)
- except AlreadyForced:
- return
+ all_virtuals = force_from_resumedata(metainterp_sd, self, deadframe,
+ vinfo, ginfo)
# The virtualizable data was stored on the real virtualizable above.
# Handle all_virtuals: keep them for later blackholing from the
# future failure of the GUARD_NOT_FORCED
diff --git a/rpython/jit/metainterp/resume.py b/rpython/jit/metainterp/resume.py
--- a/rpython/jit/metainterp/resume.py
+++ b/rpython/jit/metainterp/resume.py
@@ -19,9 +19,6 @@
# because it needs to support optimize.py which encodes virtuals with
# arbitrary cycles and also to compress the information
-class AlreadyForced(Exception):
- pass
-
class Snapshot(object):
__slots__ = ('prev', 'boxes')
diff --git a/rpython/jit/metainterp/test/test_recursive.py b/rpython/jit/metainterp/test/test_recursive.py
--- a/rpython/jit/metainterp/test/test_recursive.py
+++ b/rpython/jit/metainterp/test/test_recursive.py
@@ -774,8 +774,8 @@
def main(codeno):
frame = Frame()
frame.thing = Thing(0)
- portal(codeno, frame)
- return frame.thing.val
+ result = portal(codeno, frame)
+ return result
def portal(codeno, frame):
i = 0
@@ -791,7 +791,7 @@
s += subframe.thing.val
frame.thing = Thing(nextval + 1)
i += 1
- return frame.thing.val
+ return frame.thing.val + s
res = self.meta_interp(main, [0], inline=True)
self.check_resops(call=0, cond_call=0) # got removed by optimization
diff --git a/rpython/rlib/rthread.py b/rpython/rlib/rthread.py
--- a/rpython/rlib/rthread.py
+++ b/rpython/rlib/rthread.py
@@ -59,16 +59,18 @@
rffi.INT,
releasegil=True) # release the GIL
c_thread_releaselock = llexternal('RPyThreadReleaseLock', [TLOCKP], lltype.Void,
- releasegil=True) # release the GIL
+ _nowrapper=True) # *don't* release the GIL
# another set of functions, this time in versions that don't cause the
-# GIL to be released. To use to handle the GIL lock itself.
+# GIL to be released. Used to be there to handle the GIL lock itself,
+# but that was changed (see rgil.py). Now here for performance only.
c_thread_acquirelock_NOAUTO = llexternal('RPyThreadAcquireLock',
[TLOCKP, rffi.INT], rffi.INT,
_nowrapper=True)
-c_thread_releaselock_NOAUTO = llexternal('RPyThreadReleaseLock',
- [TLOCKP], lltype.Void,
- _nowrapper=True)
+c_thread_acquirelock_timed_NOAUTO = llexternal('RPyThreadAcquireLockTimed',
+ [TLOCKP, rffi.LONGLONG, rffi.INT],
+ rffi.INT, _nowrapper=True)
+c_thread_releaselock_NOAUTO = c_thread_releaselock
def allocate_lock():
@@ -131,9 +133,16 @@
self._lock = ll_lock
def acquire(self, flag):
- res = c_thread_acquirelock(self._lock, int(flag))
- res = rffi.cast(lltype.Signed, res)
- return bool(res)
+ if flag:
+ c_thread_acquirelock(self._lock, 1)
+ return True
+ else:
+ res = c_thread_acquirelock_timed_NOAUTO(
+ self._lock,
+ rffi.cast(rffi.LONGLONG, 0),
+ rffi.cast(rffi.INT, 0))
+ res = rffi.cast(lltype.Signed, res)
+ return bool(res)
def acquire_timed(self, timeout):
"""Timeout is in microseconds. Returns 0 in case of failure,
More information about the pypy-commit
mailing list