1.1 --- a/micropython/__init__.py Sat Sep 11 21:45:24 2010 +0200
1.2 +++ b/micropython/__init__.py Sun Sep 12 01:48:01 2010 +0200
1.3 @@ -448,18 +448,28 @@
1.4
1.5 if not self.name_references.has_key(from_name):
1.6 self.name_references[from_name] = set()
1.7 - self.name_references[from_name].add((name,))
1.8
1.9 - def use_names(self, names, from_name):
1.10 + attrnames = (name,)
1.11 + self.name_references[from_name].add((None, None, attrnames))
1.12 +
1.13 + def use_names(self, user, name, usage, from_name):
1.14
1.15 """
1.16 - Register the given 'names' as being used in the program from within an
1.17 - object with the specified 'from_name'.
1.18 + For the given attribute 'user' (which may be None if no specific user is
1.19 + given), register for the given 'name' the given attribute 'usage'
1.20 + (combinations of attribute names), noting the scope of this usage as
1.21 + being the program object with the specified 'from_name'.
1.22 """
1.23
1.24 if not self.name_references.has_key(from_name):
1.25 self.name_references[from_name] = set()
1.26 - self.name_references[from_name].add(names)
1.27 +
1.28 + all_attrnames = set()
1.29 +
1.30 + for attrnames in usage:
1.31 + all_attrnames.update(attrnames)
1.32 +
1.33 + self.name_references[from_name].add((user, name, tuple(all_attrnames)))
1.34
1.35 def use_specific_name(self, objname, attrname, from_name):
1.36
1.37 @@ -546,30 +556,42 @@
1.38 # Get name references and find possible objects which support such
1.39 # combinations of attribute names.
1.40
1.41 - for names in self.name_references.get(from_name, []):
1.42 - objnames = objtable.all_possible_objects(names)
1.43 - if not objnames:
1.44 - print "Warning: usage in %r finds no object supporting all attributes %r" % (from_name, names)
1.45 - objnames = objtable.any_possible_objects(names)
1.46 - if not objnames:
1.47 - print "Warning: usage in %r finds no object supporting any attributes %r" % (from_name, names)
1.48 + for user, name, attrnames in self.name_references.get(from_name, []):
1.49 +
1.50 + # Using all attribute names for a particular name, attempt to get
1.51 + # specific object types.
1.52 +
1.53 + objtypes = objtable.all_possible_objects_plus_status(attrnames)
1.54 + if not objtypes:
1.55 + print "Warning: usage in %r finds no object supporting all attributes %r" % (from_name, attrnames)
1.56 + objtypes = objtable.any_possible_objects_plus_status(attrnames)
1.57 + if not objtypes:
1.58 + print "Warning: usage in %r finds no object supporting any attributes %r" % (from_name, attrnames)
1.59 +
1.60 + # Record the object types for generating guards.
1.61 +
1.62 + if user is not None:
1.63 + if not hasattr(user, "_attrtypes"):
1.64 + user._attrtypes = {}
1.65 +
1.66 + user._attrtypes[name] = objtypes
1.67
1.68 # For each suggested object, consider each attribute given by the
1.69 # names.
1.70
1.71 - for objname in objnames:
1.72 - for name in names:
1.73 + for objname, is_static in objtypes:
1.74 + for attrname in attrnames:
1.75
1.76 # Visit attributes of objects known to be used.
1.77
1.78 if objname in self.attributes_used:
1.79 - self.use_attribute(objname, name)
1.80 - self._collect_attributes(objname + "." + name, objtable)
1.81 + self.use_attribute(objname, attrname)
1.82 + self._collect_attributes(objname + "." + attrname, objtable)
1.83
1.84 # Record attributes of other objects for potential visiting.
1.85
1.86 else:
1.87 - self.add_attribute_to_visit(objname, name)
1.88 + self.add_attribute_to_visit(objname, attrname)
1.89
1.90 # Get specific name references and visit the referenced objects.
1.91
2.1 --- a/micropython/ast.py Sat Sep 11 21:45:24 2010 +0200
2.2 +++ b/micropython/ast.py Sun Sep 12 01:48:01 2010 +0200
2.3 @@ -524,8 +524,7 @@
2.4
2.5 # Add any attribute usage guards.
2.6
2.7 - if self.optimiser.should_optimise_accesses_by_attribute_usage() and hasattr(node, "_attrnames"):
2.8 - self._generateGuards(node)
2.9 + self._generateGuards(node)
2.10
2.11 visitAssTuple = visitAssList
2.12
3.1 --- a/micropython/common.py Sat Sep 11 21:45:24 2010 +0200
3.2 +++ b/micropython/common.py Sun Sep 12 01:48:01 2010 +0200
3.3 @@ -61,8 +61,16 @@
3.4 if hasattr(node, "_attrusers"):
3.5 target_names = set()
3.6
3.7 + # Visit each attribute user.
3.8 +
3.9 for user in node._attrusers:
3.10 - target_names.update(self.objtable.all_possible_objects(user._attrnames[node._username]))
3.11 +
3.12 + # Since users such as branches may not provide type information,
3.13 + # attempt to find defining users.
3.14 +
3.15 + for def_user in user._attrdefs or [user]:
3.16 + for target_name, is_static in def_user._attrtypes[node._username]:
3.17 + target_names.add(target_name)
3.18
3.19 return target_names
3.20
4.1 --- a/micropython/data.py Sat Sep 11 21:45:24 2010 +0200
4.2 +++ b/micropython/data.py Sun Sep 12 01:48:01 2010 +0200
4.3 @@ -364,40 +364,39 @@
4.4 importer = module and module.importer
4.5
4.6 if importer is not None:
4.7 - for names in self.get_all_attribute_usage():
4.8 - importer.use_names(names, self.full_name())
4.9 -
4.10 - def get_all_attribute_usage(self):
4.11 -
4.12 - """
4.13 - Return a set of all usage tuples for attributes used with the different
4.14 - local names.
4.15 - """
4.16 -
4.17 - usage = set()
4.18 - for user in self.all_attribute_users:
4.19 -
4.20 - # First, visit the contributors and combine their usage with the
4.21 - # usage for each user.
4.22 -
4.23 - user._attrcombined = combined_usage = self.get_usage_from_contributors(user)
4.24 -
4.25 - for name, all_usage in combined_usage.items():
4.26 - for attrnames in all_usage:
4.27 - usage.add(tuple(attrnames))
4.28 -
4.29 - return usage
4.30 +
4.31 + # Visit each user and examine the attribute usage for each name.
4.32 +
4.33 + for user in self.all_attribute_users:
4.34 +
4.35 + # First, visit the contributors and combine their attribute
4.36 + # usage with the usage recorded directly on the user.
4.37 +
4.38 + contributors, combined_usage = self.get_usage_from_contributors(user)
4.39 + user._attrcombined = combined_usage
4.40 +
4.41 + # Record the defining user on each contributor.
4.42 +
4.43 + for contributor in contributors:
4.44 + contributor._attrdefs.append(user)
4.45 +
4.46 + # Then, tell the importer about the usage.
4.47 +
4.48 + for name, usage in combined_usage.items():
4.49 + importer.use_names(user, name, usage, self.full_name())
4.50
4.51 def get_usage_from_contributors(self, node):
4.52
4.53 """
4.54 Obtain usage information from the given 'node', combined with usage
4.55 - details from its contributors, returning a dictionary mapping names to
4.56 - lists of usage possibilities.
4.57 + details from its contributors, returning a tuple containing a set of all
4.58 + contributors employed along with a dictionary mapping names to lists of
4.59 + usage possibilities (each a collection of attribute names).
4.60 """
4.61
4.62 usage = {}
4.63 contributor_usage = {}
4.64 + all_contributors = set()
4.65
4.66 # Visit each contributor, gathering usage for each name.
4.67
4.68 @@ -407,11 +406,18 @@
4.69 # This gathers usage for each name such as {(a, b), (c, d)} and
4.70 # {(a, b), (e, f)} into a single set {(a, b), (c, d), (e, f)}.
4.71
4.72 - for name, all_usage in self.get_usage_from_contributors(contributor).items():
4.73 + contributors, contributed_usage = self.get_usage_from_contributors(contributor)
4.74 +
4.75 + for name, all_usage in contributed_usage.items():
4.76 if not contributor_usage.has_key(name):
4.77 contributor_usage[name] = set()
4.78 contributor_usage[name].update(all_usage)
4.79
4.80 + # Record all contributors.
4.81 +
4.82 + all_contributors.add(contributor)
4.83 + all_contributors.update(contributors)
4.84 +
4.85 # Then get the resulting usage.
4.86
4.87 contributed_names = contributor_usage.keys()
4.88 @@ -443,7 +449,7 @@
4.89 if name not in contributed_names:
4.90 usage[name] = set([tuple(current_usage[name])])
4.91
4.92 - return usage
4.93 + return all_contributors, usage
4.94
4.95 def use_attribute(self, name, attrname):
4.96
4.97 @@ -532,12 +538,22 @@
4.98 node._attrnames[name] = set()
4.99
4.100 def _init_attribute_user(self, node):
4.101 +
4.102 + # Attribute usage for names.
4.103 +
4.104 if not hasattr(node, "_attrnames"):
4.105 node._attrnames = {}
4.106
4.107 + # Branches contributing usage to this node.
4.108 +
4.109 if not hasattr(node, "_attrbranches"):
4.110 node._attrbranches = []
4.111
4.112 + # Definitions receiving usage from this node.
4.113 +
4.114 + if not hasattr(node, "_attrdefs"):
4.115 + node._attrdefs = []
4.116 +
4.117 # Branch management methods.
4.118
4.119 def _new_branchpoint(self):
5.1 --- a/micropython/inspect.py Sat Sep 11 21:45:24 2010 +0200
5.2 +++ b/micropython/inspect.py Sun Sep 12 01:48:01 2010 +0200
5.3 @@ -451,7 +451,13 @@
5.4 # Note usage of the attribute where a local is involved.
5.5
5.6 if expr.parent is self.get_namespace():
5.7 - node._attrusers = self.use_attribute(expr.name, attrname)
5.8 +
5.9 + # NOTE: Revisiting of nodes may occur for loops.
5.10 +
5.11 + if not hasattr(node, "_attrusers"):
5.12 + node._attrusers = set()
5.13 +
5.14 + node._attrusers.update(self.use_attribute(expr.name, attrname))
5.15 node._username = expr.name
5.16 else:
5.17 self.use_name(attrname, node.expr)
5.18 @@ -575,7 +581,13 @@
5.19 # Note usage of the attribute where a local is involved.
5.20
5.21 if expr.parent is self.get_namespace():
5.22 - node._attrusers = self.use_attribute(expr.name, node.attrname)
5.23 +
5.24 + # NOTE: Revisiting of nodes may occur for loops.
5.25 +
5.26 + if not hasattr(node, "_attrusers"):
5.27 + node._attrusers = set()
5.28 +
5.29 + node._attrusers.update(self.use_attribute(expr.name, node.attrname))
5.30 node._username = expr.name
5.31
5.32 return None
5.33 @@ -1032,10 +1044,19 @@
5.34
5.35 in_loop = self.in_loop
5.36 self.in_loop = 1
5.37 +
5.38 + # The test is evaluated initially.
5.39 +
5.40 self.dispatch(node.test)
5.41 +
5.42 self.new_branch(node)
5.43 self.dispatch(node.body)
5.44 +
5.45 + # The test is evaluated again within the loop.
5.46 +
5.47 + self.dispatch(node.test)
5.48 self.shelve_branch()
5.49 +
5.50 self.in_loop = in_loop
5.51
5.52 # Maintain a branch for the else clause.
6.1 --- a/micropython/trans.py Sat Sep 11 21:45:24 2010 +0200
6.2 +++ b/micropython/trans.py Sun Sep 12 01:48:01 2010 +0200
6.3 @@ -310,17 +310,12 @@
6.4
6.5 def _generateGuards(self, node):
6.6
6.7 - if not (self.optimiser.should_optimise_accesses_by_attribute_usage() and hasattr(node, "_attrnames")):
6.8 + if not (self.optimiser.should_optimise_accesses_by_attribute_usage() and hasattr(node, "_attrtypes")):
6.9 return
6.10
6.11 # For each name, attempt to restrict the type employed.
6.12
6.13 - for name, names_used in node._attrnames.items():
6.14 -
6.15 - # Get the names of all object types supporting these names.
6.16 -
6.17 - targets = self.objtable.all_possible_objects_plus_status(names_used)
6.18 - #found_target_names = [target_name for (target_name, is_static) in targets]
6.19 + for name, targets in node._attrtypes.items():
6.20
6.21 # NOTE: Need to merge targets using the same type but suggesting
6.22 # NOTE: different kinds of attributes (instance vs. class).
6.23 @@ -1089,8 +1084,7 @@
6.24
6.25 # Add any attribute usage guards.
6.26
6.27 - if self.optimiser.should_optimise_accesses_by_attribute_usage() and hasattr(node, "_attrnames"):
6.28 - self._generateGuards(node)
6.29 + self._generateGuards(node)
6.30
6.31 # Visit the actual code.
6.32
7.1 --- a/rsvp.py Sat Sep 11 21:45:24 2010 +0200
7.2 +++ b/rsvp.py Sun Sep 12 01:48:01 2010 +0200
7.3 @@ -182,6 +182,8 @@
7.4 location = start + i
7.5 if location == self.pc:
7.6 print "->",
7.7 + elif location in self.pc_stack:
7.8 + print "..",
7.9 else:
7.10 print " ",
7.11 print "%5d %r" % (location, x)
8.1 --- a/tests/attribute_access_type_restriction_loop_accumulation.py Sat Sep 11 21:45:24 2010 +0200
8.2 +++ b/tests/attribute_access_type_restriction_loop_accumulation.py Sun Sep 12 01:48:01 2010 +0200
8.3 @@ -19,6 +19,9 @@
8.4 def g(self):
8.5 return 3
8.6
8.7 + def h(self):
8.8 + return 4
8.9 +
8.10 class E:
8.11 def e(self):
8.12 return 4