[pypy-svn] r5274 - in pypy/trunk/src/pypy: interpreter objspace objspace/flow objspace/test

arigo at codespeak.net arigo at codespeak.net
Thu Jun 24 20:16:23 CEST 2004


Author: arigo
Date: Thu Jun 24 20:16:19 2004
New Revision: 5274

Modified:
   pypy/trunk/src/pypy/interpreter/baseobjspace.py
   pypy/trunk/src/pypy/interpreter/gateway.py
   pypy/trunk/src/pypy/objspace/flow/flowcontext.py
   pypy/trunk/src/pypy/objspace/flow/objspace.py
   pypy/trunk/src/pypy/objspace/test/test_traceobjspace.py
   pypy/trunk/src/pypy/objspace/trace.py
Log:
* Added a space.generalcache that can be used for any initialization-time
  lazy computations, populated by calls to space.loadfromcache().

* FlowObjSpace overloads loadfromcache() to performs the initialization-time 
  operations in "concrete" mode, in which only Constants may be involved and
  no operation recorded.

* This is used to build app-level Gateways.  We are closer to allow, say,
  print and raise statements in FlowObjSpace.

* TraceObjSpace needed some fixing.  Now it also ignores all loadfromcache() 
  operations, which is probably what we want.  Note that it doesn't mean 
  that operations done by the *called* app-level helper will be hidden, only
  the initial construction of this helper (which was already hidden with calls
  to settrace()).

Grumble.  Now FlowObjSpace cannot interpret app-level helpers because calling 
them packs and unpacks the arguments into a tuple, and FlowObjSpace forgets 
the length of a tuple...



Modified: pypy/trunk/src/pypy/interpreter/baseobjspace.py
==============================================================================
--- pypy/trunk/src/pypy/interpreter/baseobjspace.py	(original)
+++ pypy/trunk/src/pypy/interpreter/baseobjspace.py	Thu Jun 24 20:16:19 2004
@@ -24,9 +24,16 @@
 
     def __init__(self):
         "Basic initialization of objects."
-        # sets all the internal descriptors 
+        self.generalcache = {}
+        # sets all the internal descriptors
         self.initialize()
 
+    def loadfromcache(self, key, builder):
+        try:
+            return self.generalcache[key]
+        except KeyError:
+            return self.generalcache.setdefault(key, builder(self))
+
     def make_builtins(self, for_builtins):
         # initializing builtins may require creating a frame which in
         # turn already accesses space.w_builtins, provide a dummy one ...
@@ -82,7 +89,7 @@
 
     def getexecutioncontext(self):
         "Return what we consider to be the active execution context."
-        ec = getthreadlocals().executioncontext  #it's allways None (dec. 2003)
+        ec = getthreadlocals().executioncontext
         if ec is None:
             ec = self.createexecutioncontext()
         return ec

Modified: pypy/trunk/src/pypy/interpreter/gateway.py
==============================================================================
--- pypy/trunk/src/pypy/interpreter/gateway.py	(original)
+++ pypy/trunk/src/pypy/interpreter/gateway.py	Thu Jun 24 20:16:19 2004
@@ -11,10 +11,6 @@
 """
 
 import types
-try:
-    from weakref import WeakKeyDictionary
-except ImportError:
-    WeakKeyDictionary = dict   # XXX for PyPy
 from pypy.interpreter import eval, pycode
 from pypy.interpreter.function import Function, Method
 from pypy.interpreter.baseobjspace import Wrappable
@@ -123,9 +119,6 @@
     # explicitely as the first argument (for plain function), or is read
     # from 'self.space' for methods.
 
-    def __init__(self): 
-        self.functioncache = WeakKeyDictionary()  # map {space: Function}
-
         # after initialization the following attributes should be set
         #   name
         #   code 
@@ -138,40 +131,40 @@
         return self.get_function(space)
 
     def get_function(self, space):
-        try:
-            return self.functioncache[space]
-        except KeyError:
-            # the construction is supposed to be done only once in advance,
-            # but must be done lazily when needed only, because
-            #   1) it depends on the object space
-            #   2) the w_globals must not be built before the underlying
-            #      staticglobals is completely initialized, because
-            #      w_globals must be built only once for all the Gateway
-            #      instances of staticglobals
-            if self.staticglobals is None:
-                w_globals = None
+        return space.loadfromcache(self, self.build_all_functions)
+
+    def build_all_functions(self, space):
+        # the construction is supposed to be done only once in advance,
+        # but must be done lazily when needed only, because
+        #   1) it depends on the object space
+        #   2) the w_globals must not be built before the underlying
+        #      staticglobals is completely initialized, because
+        #      w_globals must be built only once for all the Gateway
+        #      instances of staticglobals
+        if self.staticglobals is None:
+            w_globals = None
+        else:
+            # is there another Gateway in staticglobals for which we
+            # already have a w_globals for this space ?
+            for value in self.staticglobals.itervalues():
+                if isinstance(value, Gateway):
+                    if self in space.generalcache:
+                        # yes, we share its w_globals
+                        fn = space.generalcache[value]
+                        w_globals = fn.w_func_globals
+                        break
             else:
-                # is there another Gateway in staticglobals for which we
-                # already have a w_globals for this space ?
-                for value in self.staticglobals.itervalues():
-                    if isinstance(value, Gateway):
-                        if space in value.functioncache:
-                            # yes, we share its w_globals
-                            fn = value.functioncache[space]
-                            w_globals = fn.w_func_globals
-                            break
-                else:
-                    # no, we build all Gateways in the staticglobals now.
-                    w_globals = build_dict(self.staticglobals, space)
-            return self.build_function(space, w_globals)
+                # no, we build all Gateways in the staticglobals now.
+                w_globals = build_dict(self.staticglobals, space)
+        return self.build_function(space, w_globals)
 
     def build_function(self, space, w_globals):
-        if space in self.functioncache:
-            fn = self.functioncache[space]
+        if self in space.generalcache:
+            fn = space.generalcache[self]
         else:
             defs = self.getdefaults(space)  # needs to be implemented by subclass
             fn = Function(space, self.code, w_globals, defs, forcename = self.name)
-            self.functioncache[space] = fn
+            space.generalcache[self] = fn
         return fn
 
     def get_method(self, obj):

Modified: pypy/trunk/src/pypy/objspace/flow/flowcontext.py
==============================================================================
--- pypy/trunk/src/pypy/objspace/flow/flowcontext.py	(original)
+++ pypy/trunk/src/pypy/objspace/flow/flowcontext.py	Thu Jun 24 20:16:19 2004
@@ -66,6 +66,13 @@
     def finished(self):
         return self.index == len(self.listtoreplay)
 
+class ConcreteNoOp:
+    # In "concrete mode", no SpaceOperations between Variables are allowed.
+    # Concrete mode is used to precompute lazily-initialized caches,
+    # when we don't want this precomputation to show up on the flow graph.
+    def append(self, operation):
+        raise AssertionError, "concrete mode: cannot perform %s" % operation
+
 class FlowExecutionContext(ExecutionContext):
 
     def __init__(self, space, code, globals, constargs={}, closure=None):
@@ -100,7 +107,7 @@
                                       self.closure)
 
     def bytecode_trace(self, frame):
-        if isinstance(self.crnt_ops, ReplayList):
+        if not isinstance(self.crnt_ops, list):
             return
         next_instr = frame.next_instr
         if next_instr in self.joinpoints:
@@ -140,7 +147,7 @@
             self.joinpoints[next_instr].insert(0, newblock)
 
     def guessbool(self, w_condition, cases=[False,True]):
-        if not isinstance(self.crnt_ops, ReplayList):
+        if isinstance(self.crnt_ops, list):
             block = self.crnt_block
             vars = block.getvariables()
             links = []
@@ -156,11 +163,14 @@
             # actually have block.exits[False] = elseLink and
             # block.exits[True] = ifLink.
             raise ExitFrame(None)
-        replaylist = self.crnt_ops
-        assert replaylist.finished()
-        self.crnt_block = replaylist.nextblock
-        self.crnt_ops = replaylist.nextreplaylist
-        return replaylist.booloutcome
+        if isinstance(self.crnt_ops, ReplayList):
+            replaylist = self.crnt_ops
+            assert replaylist.finished()
+            self.crnt_block = replaylist.nextblock
+            self.crnt_ops = replaylist.nextreplaylist
+            return replaylist.booloutcome
+        raise AssertionError, "concrete mode: cannot guessbool(%s)" % (
+            w_condition,)
 
     def build_flow(self):
         while self.pendingblocks:

Modified: pypy/trunk/src/pypy/objspace/flow/objspace.py
==============================================================================
--- pypy/trunk/src/pypy/objspace/flow/objspace.py	(original)
+++ pypy/trunk/src/pypy/objspace/flow/objspace.py	Thu Jun 24 20:16:19 2004
@@ -17,6 +17,7 @@
     
     def initialize(self):
         import __builtin__
+        self.concrete_mode = 0
         self.w_builtins = Constant(__builtin__.__dict__)
         self.w_None     = Constant(None)
         self.w_False    = Constant(False)
@@ -27,7 +28,27 @@
         #self.make_builtins()
         #self.make_sys()
 
+    def loadfromcache(self, key, builder):
+        try:
+            return self.generalcache[key]
+        except KeyError:
+            # this method is overloaded to allow the space to switch to
+            # "concrete mode" when building the object that goes into
+            # the cache.  In concrete mode, only Constants are allowed.
+            previous_ops = self.executioncontext.crnt_ops
+            self.executioncontext.crnt_ops = flowcontext.ConcreteNoOp()
+            self.concrete_mode += 1
+            try:
+                return self.generalcache.setdefault(key, builder(self))
+            finally:
+                self.executioncontext.crnt_ops = previous_ops
+                self.concrete_mode -= 1
+
     def newdict(self, items_w):
+        if self.concrete_mode:
+            content = [(self.unwrap(w_key), self.unwrap(w_value))
+                       for w_key, w_value in items_w]
+            return Constant(dict(content))
         flatlist_w = []
         for w_key, w_value in items_w:
             flatlist_w.append(w_key)
@@ -35,16 +56,31 @@
         return self.do_operation('newdict', *flatlist_w)
 
     def newtuple(self, args_w):
-        return self.do_operation('newtuple', *args_w)
+        try:
+            content = [self.unwrap(w_arg) for w_arg in args_w]
+        except UnwrapException:
+            return self.do_operation('newtuple', *args_w)
+        else:
+            return Constant(tuple(content))
 
     def newlist(self, args_w):
+        if self.concrete_mode:
+            content = [self.unwrap(w_arg) for w_arg in args_w]
+            return Constant(content)
         return self.do_operation('newlist', *args_w)
 
     def newslice(self, w_start=None, w_stop=None, w_step=None):
         if w_start is None: w_start = self.w_None
         if w_stop  is None: w_stop  = self.w_None
         if w_step  is None: w_step  = self.w_None
-        return self.do_operation('newslice', w_start, w_stop, w_step)
+        try:
+            content = slice(self.unwrap(w_start),
+                            self.unwrap(w_stop),
+                            self.unwrap(w_step))
+        except UnwrapException:
+            return self.do_operation('newslice', w_start, w_stop, w_step)
+        else:
+            return Constant(content)
 
     def wrap(self, obj):
         if isinstance(obj, (Variable, Constant)):

Modified: pypy/trunk/src/pypy/objspace/test/test_traceobjspace.py
==============================================================================
--- pypy/trunk/src/pypy/objspace/test/test_traceobjspace.py	(original)
+++ pypy/trunk/src/pypy/objspace/test/test_traceobjspace.py	Thu Jun 24 20:16:19 2004
@@ -14,10 +14,9 @@
 
     def perform_trace(self, app_func):
         tspace = TraceObjSpace(self.space)
-        func_gw = app2interp(app_func) 
+        func_gw = app2interp(app_func)
         func = func_gw.get_function(tspace)
-        tspace.settrace()
-        self.space.call_function(self.space.wrap(func))
+        tspace.call_function(tspace.wrap(func))
         res = tspace.getresult()
         return res 
 

Modified: pypy/trunk/src/pypy/objspace/trace.py
==============================================================================
--- pypy/trunk/src/pypy/objspace/trace.py	(original)
+++ pypy/trunk/src/pypy/objspace/trace.py	Thu Jun 24 20:16:19 2004
@@ -108,6 +108,7 @@
 
 class TraceObjSpace:
     def __init__(self, space=None):
+        self.generalcache = {}
         if space is None:
             # make up a TrivialObjSpace by default
             # ultimately, remove this hack and fix the -P option of tests
@@ -122,6 +123,19 @@
     def getresult(self):
         return self.__result
 
+    def loadfromcache(self, key, builder):
+        # hiding self.__cache.loadfromcache so that builder() can be called
+        # on self instead of self.__space, ignore the operations it performs
+        try:
+            return self.generalcache[key]
+        except KeyError:
+            saved = self.__result
+            self.settrace()
+            try:
+                return self.generalcache.setdefault(key, builder(self))
+            finally:
+                self.__result = saved
+
     def getexecutioncontext(self):
         ec = self.__space.getexecutioncontext()
         if isinstance(ec, ExecutionContextTracer):



More information about the Pypy-commit mailing list