1.1 --- a/docs/rationale.txt Mon Mar 24 23:53:18 2008 +0100
1.2 +++ b/docs/rationale.txt Mon Mar 31 00:54:03 2008 +0200
1.3 @@ -25,9 +25,29 @@
1.4 * Potentially lots of code
1.5 * Lots of executed instructions
1.6
1.7 +Improving attribute access performance
1.8 +
1.9 + * Achieve faster access using a different representation
1.10 + * Must define attributes of objects in advance
1.11 + * Restriction: modules, classes, instances are "closed"
1.12 + * Evaluate the limitations: are they too disruptive?
1.13 +
1.14 +Consequences of revised attribute access
1.15 +
1.16 + * Cannot extend the range of attributes on objects
1.17 + * Further optimisations:
1.18 + * Restriction: attempt to control modification of attributes
1.19 + * Result: further optimisation of accesses
1.20 +
1.21 +Invocations
1.22 +
1.23 + * Target checking
1.24 + * Number of arguments vs. number of parameters
1.25 + * Keyword parameter resolution
1.26 + * Defaults
1.27 +
1.28 Other costly operations
1.29
1.30 - * Keyword parameter resolution
1.31 * Binary operators
1.32 * Comparisons
1.33
2.1 --- a/micropython/__init__.py Mon Mar 24 23:53:18 2008 +0100
2.2 +++ b/micropython/__init__.py Mon Mar 31 00:54:03 2008 +0200
2.3 @@ -86,7 +86,7 @@
2.4
2.5 return self.modules.values()
2.6
2.7 - def get_image(self, with_builtins=0):
2.8 + def get_image(self, with_builtins=0, optimisations=None):
2.9
2.10 "Return a dictionary mapping modules to structures."
2.11
2.12 @@ -115,7 +115,7 @@
2.13 # Position the module in the image and make a translation.
2.14
2.15 module.location = pos
2.16 - trans = micropython.ast.Translation(module, objtable, paramtable, self.modules.get("__builtins__"))
2.17 + trans = micropython.ast.Translation(module, objtable, paramtable, self.modules.get("__builtins__"), optimisations)
2.18
2.19 # Add header details.
2.20
3.1 --- a/micropython/ast.py Mon Mar 24 23:53:18 2008 +0100
3.2 +++ b/micropython/ast.py Mon Mar 31 00:54:03 2008 +0200
3.3 @@ -48,7 +48,9 @@
3.4
3.5 "A translated module."
3.6
3.7 - def __init__(self, module, objtable, paramtable, builtins=None):
3.8 + supported_optimisations = ["constant_storage", "known_target"]
3.9 +
3.10 + def __init__(self, module, objtable, paramtable, builtins=None, optimisations=None):
3.11
3.12 """
3.13 Initialise the translation with an inspected 'module' and an attribute
3.14 @@ -62,6 +64,10 @@
3.15 self.paramtable = paramtable
3.16 self.builtins = builtins
3.17
3.18 + # Desired optimisations.
3.19 +
3.20 + self.optimisations = set(optimisations or [])
3.21 +
3.22 # The current unit being translated.
3.23
3.24 self.unit = None
3.25 @@ -205,7 +211,9 @@
3.26 # Where the last operation (defining the attribute owner) yields a
3.27 # constant...
3.28
3.29 - if isinstance(last, (LoadName, LoadAttr)) and last.attr.assignments == 1:
3.30 + if self._have_constant_input(0):
3.31 +
3.32 + # Optimise away the constant storage if appropriate.
3.33
3.34 if self._optimise_constant_storage(AttrInstruction, 1):
3.35 return
3.36 @@ -357,13 +365,14 @@
3.37 # Either test for a complete set of arguments.
3.38
3.39 if target is not None:
3.40 - nargs = len(target.positional_names)
3.41 - if len(args) < nargs:
3.42 + nargs_max = len(target.positional_names)
3.43 + nargs_min = nargs_max - len(target.defaults)
3.44 + if len(args) < nargs_min:
3.45 raise TranslateError(self.module.full_name(), node,
3.46 - "Insufficient arguments for %r: need %d arguments." % (target.name, nargs))
3.47 - elif len(args) > nargs and not target.has_star and not target.has_dstar:
3.48 + "Insufficient arguments for %r: need at least %d arguments." % (target.name, nargs_min))
3.49 + elif len(args) > nargs_max and not target.has_star and not target.has_dstar:
3.50 raise TranslateError(self.module.full_name(), node,
3.51 - "Too many arguments for %r: need %d arguments." % (target.name, nargs))
3.52 + "Too many arguments for %r: need at most %d arguments." % (target.name, nargs))
3.53
3.54 # Or generate instructions to do this at run-time.
3.55
3.56 @@ -432,7 +441,23 @@
3.57 else:
3.58 raise TranslateError(self.module.full_name(), node, "No __builtins__ module is available for name %r." % name)
3.59
3.60 - # Optimisation methods.
3.61 + # Optimisation tests.
3.62 +
3.63 + def _should_optimise_constant_storage(self):
3.64 + return "constant_storage" in self.optimisations
3.65 +
3.66 + def _should_optimise_known_target(self):
3.67 + return "known_target" in self.optimisations
3.68 +
3.69 + def _have_constant_input(self, n):
3.70 + last = self.last_ops(n+1)
3.71 + return len(last) > n and (isinstance(last[n], LoadAttr) and last[n].attr.assignments == 1 or
3.72 + isinstance(last[n], LoadConst))
3.73 +
3.74 + def _have_known_target(self):
3.75 + return self._have_constant_input(0)
3.76 +
3.77 + # Optimisation methods. See the supported_optimisations class attribute.
3.78
3.79 def _optimise_constant_storage(self, cls, n):
3.80
3.81 @@ -441,12 +466,8 @@
3.82 also constant, optimise away both operations.
3.83 """
3.84
3.85 - last = self.last_ops(n+1)
3.86 -
3.87 - if cls in (StoreAttr, StoreName) and len(last) > n and \
3.88 - (isinstance(last[n], LoadAttr) and last[n].attr.assignments == 1 or
3.89 - isinstance(last[n], LoadConst)):
3.90 -
3.91 + if self._should_optimise_constant_storage() and cls in (StoreAttr, StoreName) and \
3.92 + self._have_constant_input(n) and self._have_constant_input(n-1):
3.93 self.remove_ops(n+1)
3.94 return 1
3.95 else:
3.96 @@ -460,8 +481,8 @@
3.97 appropriate, get information about the specific initialiser.
3.98 """
3.99
3.100 - last = self.last_op()
3.101 - if isinstance(last, (LoadName, LoadAttr)) and last.attr.assignments == 1:
3.102 + if self._should_optimise_known_target() and self._have_known_target():
3.103 + last = self.last_op()
3.104 target = last.attr.value
3.105 context = last.attr.parent
3.106
4.1 --- a/micropython/inspect.py Mon Mar 24 23:53:18 2008 +0100
4.2 +++ b/micropython/inspect.py Mon Mar 31 00:54:03 2008 +0200
4.3 @@ -571,11 +571,12 @@
4.4
4.5 "An inspected function."
4.6
4.7 - def __init__(self, name, parent, argnames, has_star, has_dstar, global_namespace=None, node=None):
4.8 + def __init__(self, name, parent, argnames, defaults, has_star, has_dstar, global_namespace=None, node=None):
4.9 NamespaceDict.__init__(self, global_namespace)
4.10 self.name = name
4.11 self.parent = parent
4.12 self.argnames = argnames
4.13 + self.defaults = defaults
4.14 self.positional_names = self.argnames[:]
4.15 if has_dstar:
4.16 self.dstar_name = self.positional_names[-1]
4.17 @@ -609,12 +610,12 @@
4.18
4.19 def __repr__(self):
4.20 if self.location is not None:
4.21 - return "Function(%r, %r, %r, %r, %r, location=%r)" % (
4.22 - self.name, self.parent, self.argnames, self.has_star, self.has_dstar, self.location
4.23 + return "Function(%r, %r, %r, %r, %r, %r, location=%r)" % (
4.24 + self.name, self.parent, self.argnames, self.defaults, self.has_star, self.has_dstar, self.location
4.25 )
4.26 else:
4.27 - return "Function(%r, %r, %r, %r, %r)" % (
4.28 - self.name, self.parent, self.argnames, self.has_star, self.has_dstar
4.29 + return "Function(%r, %r, %r, %r, %r, %r)" % (
4.30 + self.name, self.parent, self.argnames, self.defaults, self.has_star, self.has_dstar
4.31 )
4.32
4.33 def make_global(self, name):
4.34 @@ -679,7 +680,8 @@
4.35
4.36 "Make a function from a method."
4.37
4.38 - return Function(self.name, self.parent, self.argnames[1:], self.has_star, self.has_dstar, self.global_namespace, self.node)
4.39 + return Function(self.name, self.parent, self.argnames[1:], self.defaults,
4.40 + self.has_star, self.has_dstar, self.global_namespace, self.node)
4.41
4.42 class UnresolvedName(NamespaceDict):
4.43
4.44 @@ -1030,6 +1032,7 @@
4.45 node.name,
4.46 self.get_parent(),
4.47 node.argnames,
4.48 + node.defaults,
4.49 (node.flags & 4 != 0),
4.50 (node.flags & 8 != 0),
4.51 self,
5.1 --- a/test.py Mon Mar 24 23:53:18 2008 +0100
5.2 +++ b/test.py Mon Mar 31 00:54:03 2008 +0200
5.3 @@ -3,27 +3,34 @@
5.4 import micropython
5.5 import sys
5.6
5.7 -def show(importer, with_builtins=0):
5.8 - for i, x in enumerate(importer.get_image(with_builtins=with_builtins)):
5.9 +def show(importer, with_builtins=0, optimisations=None):
5.10 + optimisations = optimisations or requested_optimisations
5.11 + for i, x in enumerate(importer.get_image(with_builtins, optimisations)):
5.12 print i, x
5.13
5.14 def attrs(obj):
5.15 for name, attr in obj.items():
5.16 print name, attr
5.17
5.18 -i = micropython.Importer(sys.path, "-v" in sys.argv)
5.19 -try:
5.20 - builtins = i.load_from_file("lib/builtins.py", "__builtins__")
5.21 - if len(sys.argv) < 2:
5.22 - m = i.load("micropython")
5.23 - #m = i.load_from_file("micropython/__init__.py")
5.24 +if __name__ == "__main__":
5.25 + requested_optimisations = []
5.26 + for arg in sys.argv[2:]:
5.27 + if arg.startswith("-o"):
5.28 + requested_optimisations.append(arg[2:])
5.29 +
5.30 + i = micropython.Importer(sys.path, "-v" in sys.argv)
5.31 + try:
5.32 + builtins = i.load_from_file("lib/builtins.py", "__builtins__")
5.33 + if len(sys.argv) < 2:
5.34 + m = i.load("micropython")
5.35 + #m = i.load_from_file("micropython/__init__.py")
5.36 + else:
5.37 + m = i.load_from_file(sys.argv[1])
5.38 + except micropython.ProcessingError, exc:
5.39 + print repr(exc)
5.40 else:
5.41 - m = i.load_from_file(sys.argv[1])
5.42 -except micropython.ProcessingError, exc:
5.43 - print repr(exc)
5.44 -else:
5.45 - i.vacuum()
5.46 - ot = i.get_object_table()
5.47 - pt = i.get_parameter_table()
5.48 + i.vacuum()
5.49 + ot = i.get_object_table()
5.50 + pt = i.get_parameter_table()
5.51
5.52 # vim: tabstop=4 expandtab shiftwidth=4
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
6.2 +++ b/tests/call_func_default.py Mon Mar 31 00:54:03 2008 +0200
6.3 @@ -0,0 +1,21 @@
6.4 +#!/usr/bin/env python
6.5 +
6.6 +def f(a, b, c=4):
6.7 + pass
6.8 +
6.9 +f(1, 2, 3)
6.10 +f(1, b=2, c=3)
6.11 +f(c=3, b=2, a=1)
6.12 +f(1, 2)
6.13 +
6.14 +g = f
6.15 +g(1, c=3, b=2)
6.16 +g(1, 2)
6.17 +
6.18 +def g(a, c, b=5):
6.19 + pass
6.20 +
6.21 +g(1, c=3, b=2)
6.22 +g(1, 3)
6.23 +
6.24 +# vim: tabstop=4 expandtab shiftwidth=4