[pypy-commit] pypy framestate: Refactor FrameState

rlamy noreply at buildbot.pypy.org
Fri Nov 21 00:57:17 CET 2014


Author: Ronan Lamy <ronan.lamy at gmail.com>
Branch: framestate
Changeset: r74622:06b064a032d8
Date: 2014-11-20 23:48 +0000
http://bitbucket.org/pypy/pypy/changeset/06b064a032d8/

Log:	Refactor FrameState

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
@@ -342,28 +341,14 @@
         del self.stack[finaldepth:]
 
     def getstate(self, next_offset):
-        data = self.locals_w[:]
-        data.extend(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 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.locals_w = data[:self.nlocals]
-        self.stack = data[self.nlocals:-2]
-        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()
 
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,47 @@
-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
 
+    @property
+    def mergeable(self):
+        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)]
@@ -38,13 +64,21 @@
            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:
+                exc = other.last_exception
+            elif other.last_exception is None:
+                exc = self.last_exception
+            else:
+                e1 = self.last_exception
+                e2 = other.last_exception
+                exc = FSException(union(e1.w_type, e2.w_type),
+                        union(e1.w_value, e2.w_value))
         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 +95,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,17 +104,17 @@
     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__))
 
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


More information about the pypy-commit mailing list