[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