[pypy-svn] rev 901 - in pypy/trunk/src/pypy: interpreter objspace/ann objspace/ann/test tool

gvanrossum at codespeak.net gvanrossum at codespeak.net
Sun Jun 22 11:36:29 CEST 2003


Author: gvanrossum
Date: Sun Jun 22 11:36:28 2003
New Revision: 901

Added:
   pypy/trunk/src/pypy/objspace/ann/cloningcontext.py   (contents, props changed)
Modified:
   pypy/trunk/src/pypy/interpreter/baseobjspace.py
   pypy/trunk/src/pypy/interpreter/executioncontext.py
   pypy/trunk/src/pypy/interpreter/pyframe.py
   pypy/trunk/src/pypy/objspace/ann/objspace.py
   pypy/trunk/src/pypy/objspace/ann/test/test_simple.py
   pypy/trunk/src/pypy/tool/methodChecker.py   (props changed)
Log:
Clone the frame when in indeterminate 'if' is found.

Modified: pypy/trunk/src/pypy/interpreter/baseobjspace.py
==============================================================================
--- pypy/trunk/src/pypy/interpreter/baseobjspace.py	(original)
+++ pypy/trunk/src/pypy/interpreter/baseobjspace.py	Sun Jun 22 11:36:28 2003
@@ -50,9 +50,13 @@
         "Return what we consider to be the active execution context."
         ec = threadlocals.getlocals().executioncontext
         if ec is None:
-            ec = ExecutionContext(self)
+            ec = self.createexecutioncontext()
         return ec
 
+    def createexecutioncontext(self):
+        "Factory function for execution contexts."
+        return ExecutionContext(self)
+
     def gethelper(self, applicationfile):
         try:
             helper = self.appfile_helpers[applicationfile]

Modified: pypy/trunk/src/pypy/interpreter/executioncontext.py
==============================================================================
--- pypy/trunk/src/pypy/interpreter/executioncontext.py	(original)
+++ pypy/trunk/src/pypy/interpreter/executioncontext.py	Sun Jun 22 11:36:28 2003
@@ -226,6 +226,11 @@
     def empty(self):
         return not self.items
 
+    def clone(self):
+        s = Stack()
+        s.items = self.items[:]
+        return s
+
 
 # installing the excepthook for OperationErrors
 def operr_excepthook(exctype, value, traceback):

Modified: pypy/trunk/src/pypy/interpreter/pyframe.py
==============================================================================
--- pypy/trunk/src/pypy/interpreter/pyframe.py	(original)
+++ pypy/trunk/src/pypy/interpreter/pyframe.py	Sun Jun 22 11:36:28 2003
@@ -30,6 +30,16 @@
         self.last_exception = None
         self.next_instr = 0
 
+    def clone(self):
+        f = PyFrame(self.space, self.bytecode, self.w_globals, self.w_locals)
+        f.valuestack = self.valuestack.clone()
+        f.blockstack = self.blockstack.clone()
+        f.last_exception = self.last_exception
+        f.next_instr = self.next_instr
+        # Clone the locals (only the annotation space implements this)
+        f.w_locals = self.space.clone_locals(self.w_locals)
+        return f
+
     def eval(self, executioncontext):
         "Interpreter main loop!"
         from pypy.interpreter import opcode
@@ -60,7 +70,7 @@
                 except ControlFlowException, ctlflowexc:
                     # we have a reason to change the control flow
                     # (typically unroll the stack)
-                    ctlflowexc.action(self)
+                    ctlflowexc.action(self, last_instr)
             
         except ExitFrame, e:
             # leave that frame
@@ -251,7 +261,7 @@
 		WHY_YIELD	SYieldValue
 
     """
-    def action(self, frame):
+    def action(self, frame, last_instr):
         "Default unroller implementation."
         try:
             while not frame.blockstack.empty():
@@ -292,7 +302,7 @@
 class SYieldValue(ControlFlowException):
     """Signals a 'yield' statement.
     Argument is the wrapped object to return."""
-    def action(self, frame):
+    def action(self, frame, last_instr):
         # XXX generators
         raise OperationError(frame.space.w_Exception,
                              frame.space.wrap("generators are not ready yet"))

Added: pypy/trunk/src/pypy/objspace/ann/cloningcontext.py
==============================================================================
--- (empty file)
+++ pypy/trunk/src/pypy/objspace/ann/cloningcontext.py	Sun Jun 22 11:36:28 2003
@@ -0,0 +1,44 @@
+from pypy.interpreter.executioncontext import ExecutionContext
+from pypy.interpreter.pyframe import ControlFlowException
+
+class IndeterminateCondition(ControlFlowException):
+
+    def __init__(self, w_obj):
+        ControlFlowException.__init__(self)
+        self.w_obj = w_obj
+
+    def action(self, frame, last_instr):
+        frame.next_instr = last_instr
+        f2 = frame.clone()
+        clones = frame.clones
+        clones.append(f2)
+        f2.clones = clones # Share the joy
+        f2.force_w_obj = self.w_obj
+        self.w_obj.force = True
+
+class CloningExecutionContext(ExecutionContext):
+
+    lastframe = None
+
+    def bytecode_trace(self, frame):
+        self.lastframe = frame
+
+    def eval_frame(self, frame):
+        from pypy.objspace.ann.objspace import W_Anything
+        assert not hasattr(frame, "clones")
+        space = frame.space
+        clones = [frame]
+        frame.clones = clones
+        frame.force_w_obj = None
+        result = None # W_Impossible
+        while clones:
+            f = clones.pop()
+            w_obj = f.force_w_obj
+            if w_obj is not None:
+                assert w_obj.force == True
+                w_obj.force = False
+            r = ExecutionContext.eval_frame(self, f)
+            result = space.union(result, r)
+            if isinstance(result, W_Anything):
+                break
+        return result

Modified: pypy/trunk/src/pypy/objspace/ann/objspace.py
==============================================================================
--- pypy/trunk/src/pypy/objspace/ann/objspace.py	(original)
+++ pypy/trunk/src/pypy/objspace/ann/objspace.py	Sun Jun 22 11:36:28 2003
@@ -4,6 +4,8 @@
 from pypy.interpreter.baseobjspace \
      import ObjSpace, OperationError, NoValue, PyPyError
 from pypy.interpreter.pycode import PyByteCode
+from pypy.objspace.ann.cloningcontext import CloningExecutionContext
+from pypy.objspace.ann.cloningcontext import IndeterminateCondition
 
 
 class W_Object(object):
@@ -28,11 +30,20 @@
         return len(self.args_w)
     def __getitem__(self, i):
         return self.args_w[i]
+    def clone(self):
+        args_w = self.args_w
+        if isinstance(args_w, dict):
+            args_w = args_w.copy()
+        # XXX Recurse down the values?
+        return W_KnownKeysContainer(args_w)
 
 
 class AnnException(Exception):
     pass
 
+class UnwrapException(AnnException):
+    pass
+
 
 class AnnotationObjSpace(ObjSpace):
 
@@ -48,7 +59,7 @@
                 setattr(self, 'w_' + c.__name__, self.wrap(c))
         self.w_builtins = self.wrap(__builtin__)
 
-    # Service methods
+    # Service methods whose interface is in the abstract base class
 
     def wrap(self, obj):
         return W_Constant(obj)
@@ -57,21 +68,59 @@
         if isinstance(w_obj, W_Constant):
             return w_obj.value
         elif isinstance(w_obj, W_Object):
-            raise AnnException, "Cannot unwrap %r" % w_obj
+            raise UnwrapException("Cannot unwrap: " +repr(w_obj))
         else:
-            raise TypeError, "not wrapped: %s" % repr(w_obj)
-
-    def is_true(self, w_obj):
-        if isinstance(w_obj, W_KnownKeysContainer):
-            return bool(len(w_obj))
-        obj = self.unwrap(w_obj)
-        return bool(obj)
+            raise TypeError("not wrapped: " + repr(w_obj))
 
     def reraise(self):
         t, v = sys.exc_info()[:2]
         raise OperationError(self.wrap(t), self.wrap(v))
 
-    # Specialized creators
+    def is_true(self, w_obj):
+        if hasattr(w_obj, "force"):
+            return w_obj.force # Forced by cloning machinery
+        if isinstance(w_obj, W_KnownKeysContainer):
+            return bool(len(w_obj))
+        try:
+            obj = self.unwrap(w_obj)
+        except UnwrapException:
+            pass
+        else:
+            return bool(obj)
+        # It's indeterminate!!!  Aargh!!!
+        # Raise an exception that will clone the interpreter.
+        raise IndeterminateCondition(w_obj)
+
+    def createexecutioncontext(self):
+        return CloningExecutionContext(self)
+
+    def clone_locals(self, w_locals):
+        assert isinstance(w_locals, W_KnownKeysContainer)
+        return w_locals.clone()
+
+    def union(self, r1, r2):
+        # Unite two results
+        if r1 is r2:
+            return r1
+        if r1 is None:
+            return r2
+        if r2 is None:
+            return r1
+        if isinstance(r1, W_Anything) or isinstance(r2, W_Anything):
+            return W_Anything()
+        if (isinstance(r1, W_Constant) and isinstance(r2, W_Constant) and
+            r1.value == r2.value):
+            return W_Constant(r1.value)
+        if self.is_int(r1) and self.is_int(r2):
+            return W_Integer()
+        if (isinstance(r1, W_KnownKeysContainer) and
+            isinstance(r2, W_KnownKeysContainer) and
+            r1.args_w == r2.args_w):
+            return W_KnownKeysContainer(r1.args_w)
+        # XXX Could do more cases.  This will blow up as we add more types
+        return W_Anything()
+
+    # Specialized creators whose interface is in the abstract base class
     
     def newtuple(self, args_w):
         for w_arg in args_w:
@@ -84,7 +133,7 @@
         for w_key, w_value in items_w:
             try:
                 key = self.unwrap(w_key)
-            except AnnException:
+            except UnwrapException:
                 break
             else:
                 values_w[key] = w_value
@@ -105,7 +154,7 @@
         try:
             left = self.unwrap(w_left)
             right = self.unwrap(w_right)
-        except AnnException:
+        except UnwrapException:
             pass
         else:
             return self.wrap(left + right)
@@ -141,7 +190,7 @@
         try:
             obj = self.unwrap(w_obj)
             name = self.unwrap(w_name)
-        except AnnException:
+        except UnwrapException:
             return W_Anything()
         else:
             try:
@@ -154,7 +203,7 @@
             return self.wrap(len(w_obj))
         try:
             obj = self.unwrap(w_obj)
-        except AnnException:
+        except UnwrapException:
             return W_Anything()
         else:
             return self.wrap(len(obj))
@@ -162,11 +211,11 @@
     def getitem(self, w_obj, w_key):
         try:
             key = self.unwrap(w_key)
-        except AnnException:
+        except UnwrapException:
             return W_Anything()
         try:
             obj = self.unwrap(w_obj)
-        except AnnException:
+        except UnwrapException:
             if isinstance(w_obj, W_KnownKeysContainer):
                 return w_obj[key]
             else:

Modified: pypy/trunk/src/pypy/objspace/ann/test/test_simple.py
==============================================================================
--- pypy/trunk/src/pypy/objspace/ann/test/test_simple.py	(original)
+++ pypy/trunk/src/pypy/objspace/ann/test/test_simple.py	Sun Jun 22 11:36:28 2003
@@ -2,23 +2,23 @@
 from pypy.tool import test
 from pypy.objspace.ann.objspace import W_Object, W_Anything, W_Integer
 from pypy.objspace.ann.objspace import AnnotationObjSpace
-from pypy.interpreter import baseobjspace, executioncontext, pyframe
+from pypy.interpreter import baseobjspace, pyframe
 
 class TestAnnotationObjSpace(test.TestCase):
 
     def codetest(self, source, functionname, args_w):
         """Compile and run the given code string, and then call its function
         named by 'functionname' with a list of wrapped arguments 'args_w'.
-        It returns the wrapped result."""
+        Return the wrapped result."""
 
         glob = {}
         exec source in glob
+        func = glob[functionname]
 
-        space = self.space
-        w_args = space.newtuple(args_w)
-        w_func = space.wrap(glob[functionname])
-        w_kwds = space.newdict([])
-        return space.call(w_func, w_args, w_kwds)
+        w_args = self.space.newtuple(args_w)
+        w_func = self.space.wrap(func)
+        w_kwds = self.space.newdict([])
+        return self.space.call(w_func, w_args, w_kwds)
 
     def setUp(self):
         self.space = AnnotationObjSpace()
@@ -47,6 +47,24 @@
                           'f', [W_Integer()])
         self.assertEquals(type(x), W_Integer)
 
+    def test_conditional_1(self):
+        x = self.codetest("def f(i):\n"
+                          "    if i < 0:\n"
+                          "        return 0\n"
+                          "    else:\n"
+                          "        return 1\n",
+                          'f', [W_Integer()])
+        self.assertEquals(type(x), W_Integer)
+
+    def test_conditional_2(self):
+        x = self.codetest("def f(i):\n"
+                          "    if i < 0:\n"
+                          "        return 0\n"
+                          "    else:\n"
+                          "        return 0\n",
+                          'f', [W_Integer()])
+        self.assertEquals(self.space.unwrap(x), 0)
+
 
 
 if __name__ == '__main__':


More information about the Pypy-commit mailing list