[Zope-Checkins] CVS: Zope/lib/python/RestrictedPython/compiler_2_1 - misc.py:1.2.76.1 pyassem.py:1.2.76.1 symbols.py:1.2.76.1 transformer.py:1.2.76.1 visitor.py:1.2.76.1
Shane Hathaway
shane@cvs.zope.org
Thu, 8 Aug 2002 14:49:26 -0400
Update of /cvs-repository/Zope/lib/python/RestrictedPython/compiler_2_1
In directory cvs.zope.org:/tmp/cvs-serv20389/compiler_2_1
Modified Files:
Tag: shane-leaks-repair-branch
misc.py pyassem.py symbols.py transformer.py visitor.py
Log Message:
With much help from Cyclops, removed all the cyclic references in the compiler
package that can be discovered by the unit tests. Used weak references in most
places, _break_cr() methods in other places, and even a "tuple lookalike" in
one place.
There may be other cycles, but they aren't likely to be so frequent.
Note that this corrects only the Python 2.1 version of the compiler.
Python 2.2's compiler will have to be fixed independently.
=== Zope/lib/python/RestrictedPython/compiler_2_1/misc.py 1.2 => 1.2.76.1 ===
--- Zope/lib/python/RestrictedPython/compiler_2_1/misc.py:1.2 Fri Dec 21 14:34:48 2001
+++ Zope/lib/python/RestrictedPython/compiler_2_1/misc.py Thu Aug 8 14:49:25 2002
@@ -1,4 +1,5 @@
import types
+from weakref import WeakKeyDictionary, ref
def flatten(tup):
elts = []
@@ -28,6 +29,28 @@
c = Set()
c.elts.update(self.elts)
return c
+
+
+class WeakSet (WeakKeyDictionary):
+ __contains__ = WeakKeyDictionary.has_key
+ has_elt = WeakKeyDictionary.has_key
+ elements = WeakKeyDictionary.keys
+
+ # __init__ is based on Python 2.2's WeakDictionary implementation.
+ def __init__(self):
+ self.data = {}
+ def remove(k, selfref=ref(self)):
+ self = selfref()
+ if self is not None:
+ del self.data[k]
+ self._remove = remove
+
+ def add(self, elt):
+ self[elt] = 1
+
+ def remove(self, key):
+ del self.data[ref(key)]
+
class Stack:
def __init__(self):
=== Zope/lib/python/RestrictedPython/compiler_2_1/pyassem.py 1.2 => 1.2.76.1 ===
--- Zope/lib/python/RestrictedPython/compiler_2_1/pyassem.py:1.2 Fri Dec 21 14:34:48 2001
+++ Zope/lib/python/RestrictedPython/compiler_2_1/pyassem.py Thu Aug 8 14:49:25 2002
@@ -7,6 +7,7 @@
import string
import sys
import types
+from weakref import ref
import misc
from consts import CO_OPTIMIZED, CO_NEWLOCALS, CO_VARARGS, CO_VARKEYWORDS
@@ -231,8 +232,8 @@
def __init__(self, label=''):
self.insts = []
- self.inEdges = misc.Set()
- self.outEdges = misc.Set()
+ self.inEdges = misc.WeakSet()
+ self.outEdges = misc.WeakSet()
self.label = label
self.bid = Block._count
self.next = []
@@ -253,6 +254,7 @@
op = inst[0]
if op[:4] == 'JUMP':
self.outEdges.add(inst[1])
+ inst = BlockRefInstruction(inst)
self.insts.append(inst)
def getInstructions(self):
@@ -311,6 +313,23 @@
if hasattr(op, 'graph'):
contained.append(op.graph)
return contained
+
+
+class BlockRefInstruction:
+ """Tuple-like object that makes a weak reference to the block."""
+
+ def __init__(self, inst):
+ self._data = (inst[0], ref(inst[1]),) + inst[2:]
+
+ def __len__(self):
+ return len(self._data)
+
+ def __getitem__(self, index):
+ if index == 1:
+ return self._data[1]()
+ else:
+ return self._data[index]
+
# flags for code objects
@@ -403,6 +422,20 @@
if io:
sys.stdout = save
+ def _max_depth(self, b, d, depth, seen):
+ if seen.has_key(b):
+ return d
+ seen[b] = 1
+ d = d + depth[b]
+ children = b.get_children()
+ if children:
+ return max([self._max_depth(c, d, depth, seen) for c in children])
+ else:
+ if not b.label == "exit":
+ return self._max_depth(self.exit, d, depth, seen)
+ else:
+ return d
+
def computeStackDepth(self):
"""Compute the max stack depth.
@@ -417,21 +450,7 @@
seen = {}
- def max_depth(b, d):
- if seen.has_key(b):
- return d
- seen[b] = 1
- d = d + depth[b]
- children = b.get_children()
- if children:
- return max([max_depth(c, d) for c in children])
- else:
- if not b.label == "exit":
- return max_depth(self.exit, d)
- else:
- return d
-
- self.stacksize = max_depth(self.entry, 0)
+ self.stacksize = self._max_depth(self.entry, 0, depth, seen)
def flattenGraph(self):
"""Arrange the blocks in order and resolve jumps"""
=== Zope/lib/python/RestrictedPython/compiler_2_1/symbols.py 1.2 => 1.2.76.1 ===
--- Zope/lib/python/RestrictedPython/compiler_2_1/symbols.py:1.2 Fri Dec 21 14:34:48 2001
+++ Zope/lib/python/RestrictedPython/compiler_2_1/symbols.py Thu Aug 8 14:49:25 2002
@@ -4,6 +4,7 @@
from consts import SC_LOCAL, SC_GLOBAL, SC_FREE, SC_CELL, SC_UNKNOWN
from misc import mangle
import types
+from weakref import proxy
import sys
@@ -13,7 +14,7 @@
# XXX how much information do I need about each name?
def __init__(self, name, module, klass=None):
self.name = name
- self.module = module
+ self.module = proxy(module)
self.defs = {}
self.uses = {}
self.globals = {}
=== Zope/lib/python/RestrictedPython/compiler_2_1/transformer.py 1.2 => 1.2.76.1 ===
--- Zope/lib/python/RestrictedPython/compiler_2_1/transformer.py:1.2 Fri Dec 21 14:34:48 2001
+++ Zope/lib/python/RestrictedPython/compiler_2_1/transformer.py Thu Aug 8 14:49:25 2002
@@ -43,7 +43,10 @@
return parse(src)
def parse(buf):
- return Transformer().parsesuite(buf)
+ t = Transformer()
+ res = t.parsesuite(buf)
+ t._break_cr()
+ return res
def asList(nodes):
l = []
@@ -1198,6 +1201,11 @@
if n in _doc_nodes and len(node) == 1:
return self.get_docstring(node[0])
return None
+
+ def _break_cr(self):
+ # Break circular references for faster garbage collection
+ del self._dispatch
+ del self._atom_dispatch
_doc_nodes = [
=== Zope/lib/python/RestrictedPython/compiler_2_1/visitor.py 1.2 => 1.2.76.1 ===
--- Zope/lib/python/RestrictedPython/compiler_2_1/visitor.py:1.2 Fri Dec 21 14:34:48 2001
+++ Zope/lib/python/RestrictedPython/compiler_2_1/visitor.py Thu Aug 8 14:49:25 2002
@@ -71,6 +71,14 @@
_preorder = dispatch
+ def _break_cr(self):
+ # Break circular references for faster garbage collection
+ del self.node
+ del self._cache
+ del self.visitor.visit
+ del self.visitor
+
+
class ExampleASTVisitor(ASTVisitor):
"""Prints examples of the nodes that aren't visited
@@ -110,7 +118,9 @@
if verbose is not None:
w.VERBOSE = verbose
w.preorder(tree, visitor)
- return w.visitor
+ res = w.visitor
+ w._break_cr()
+ return res
def dumpNode(node):
print node.__class__