2.1 --- a/optimiser.py Wed Mar 01 17:17:27 2017 +0100
2.2 +++ b/optimiser.py Thu Mar 02 01:30:39 2017 +0100
2.3 @@ -20,14 +20,14 @@
2.4 """
2.5
2.6 from common import add_counter_item, get_attrname_from_location, init_item, \
2.7 - sorted_output
2.8 + sorted_output, CommonOutput
2.9 from encoders import digest, encode_access_location, encode_instruction, get_kinds
2.10 from errors import OptimiseError
2.11 from os.path import exists, join
2.12 from os import makedirs
2.13 -from referencing import Reference
2.14 +from referencing import decode_reference, Reference
2.15
2.16 -class Optimiser:
2.17 +class Optimiser(CommonOutput):
2.18
2.19 "Optimise objects in a program."
2.20
2.21 @@ -43,23 +43,35 @@
2.22 self.deducer = deducer
2.23 self.output = output
2.24
2.25 + # Detection of differences between any existing structure or signature
2.26 + # information and the generated information.
2.27 +
2.28 + self.differing_structures = []
2.29 + self.differing_parameters = []
2.30 +
2.31 # Locations/offsets of attributes in objects.
2.32
2.33 self.locations = None
2.34 + self.existing_locations = None
2.35 +
2.36 self.attr_locations = None
2.37 - self.all_attrnames = None
2.38
2.39 - self.existing_locations = []
2.40 - self.existing_attrnames = []
2.41 + # Attribute code assignments.
2.42 +
2.43 + self.all_attrnames = None
2.44 + self.existing_attrnames = None
2.45
2.46 # Locations of parameters in parameter tables.
2.47
2.48 self.arg_locations = None
2.49 + self.existing_arg_locations = None
2.50 +
2.51 self.param_locations = None
2.52 - self.all_paramnames = None
2.53
2.54 - self.existing_arg_locations = []
2.55 - self.existing_paramnames = []
2.56 + # Parameter code assignments.
2.57 +
2.58 + self.all_paramnames = None
2.59 + self.existing_paramnames = None
2.60
2.61 # Specific attribute access information.
2.62
2.63 @@ -69,11 +81,13 @@
2.64 # Object structure information.
2.65
2.66 self.structures = {}
2.67 + self.existing_structures = None
2.68 self.attr_table = {}
2.69
2.70 # Parameter list information.
2.71
2.72 self.parameters = {}
2.73 + self.existing_parameters = None
2.74 self.param_table = {}
2.75
2.76 # Constant literal information.
2.77 @@ -96,14 +110,37 @@
2.78 self.populate_constants()
2.79 self.initialise_access_instructions()
2.80
2.81 + def need_reset(self):
2.82 +
2.83 + """
2.84 + Return whether attribute or parameter information has changed, requiring
2.85 + the reset/recompilation of all source files.
2.86 + """
2.87 +
2.88 + return self.differing_structures or self.differing_parameters
2.89 +
2.90 def from_output(self):
2.91
2.92 "Read input files that influence optimisation."
2.93
2.94 - self.read_locations("locations", self.existing_locations, self._line_to_list, list)
2.95 - self.read_locations("parameter_locations", self.existing_arg_locations, self._line_to_list, list)
2.96 - self.read_locations("attrnames", self.existing_attrnames, lambda x: x, lambda x: None)
2.97 - self.read_locations("paramnames", self.existing_paramnames, lambda x: x, lambda x: None)
2.98 + # Remove any output for a different program.
2.99 +
2.100 + self.check_output()
2.101 +
2.102 + # Existing attribute and parameter positioning information.
2.103 +
2.104 + self.existing_locations = self.read_locations("locations", self._line_to_list, list)
2.105 + self.existing_arg_locations = self.read_locations("parameter_locations", self._line_to_list, list)
2.106 +
2.107 + # Existing attribute and parameter code information.
2.108 +
2.109 + self.existing_attrnames = self.read_locations("attrnames", lambda x: x, lambda x: None)
2.110 + self.existing_paramnames = self.read_locations("paramnames", lambda x: x, lambda x: None)
2.111 +
2.112 + # Existing structure and signature information.
2.113 +
2.114 + self.existing_structures = dict(self.read_locations("structures", self._line_to_structure_pairs, list))
2.115 + self.existing_parameters = dict(self.read_locations("parameters", self._line_to_signature_pairs, list))
2.116
2.117 def _line_to_list(self, line):
2.118
2.119 @@ -111,15 +148,39 @@
2.120
2.121 return line.split(", ")
2.122
2.123 - def read_locations(self, filename, collection, decode, empty):
2.124 + def _line_to_signature_pairs(self, line):
2.125 +
2.126 + "Convert comma-separated values in 'line' to a list of pairs of values."
2.127 +
2.128 + l = []
2.129 + objpath, line = line.split(" ", 1)
2.130 + for values in line.split(", "):
2.131 + if values != "-":
2.132 + name, pos = values.split(":")
2.133 + l.append((name, int(pos)))
2.134 + else:
2.135 + l.append(None)
2.136 + return (objpath, l)
2.137 +
2.138 + def _line_to_structure_pairs(self, line):
2.139 +
2.140 + "Convert comma-separated values in 'line' to a list of pairs of values."
2.141 +
2.142 + l = []
2.143 + ref, line = line.split(" ", 1)
2.144 + values = map(lambda x: x != '-' and x or None, line.split(", "))
2.145 + return (decode_reference(ref), values)
2.146 +
2.147 + def read_locations(self, filename, decode, empty):
2.148
2.149 """
2.150 - Read location details from 'filename' into 'collection', using 'decode'
2.151 - to convert each line and 'empty' to produce an empty result where no
2.152 - data is given on a line.
2.153 + Read location details from 'filename', using 'decode' to convert each
2.154 + line and 'empty' to produce an empty result where no data is given on a
2.155 + line, returning a collection.
2.156 """
2.157
2.158 filename = join(self.output, filename)
2.159 + collection = []
2.160
2.161 if exists(filename):
2.162 f = open(filename)
2.163 @@ -135,6 +196,8 @@
2.164 finally:
2.165 f.close()
2.166
2.167 + return collection
2.168 +
2.169 def to_output(self):
2.170
2.171 "Write the output files using optimisation information."
2.172 @@ -401,12 +464,19 @@
2.173 for (objkind, name), attrnames in self.all_attrs.items():
2.174 key = Reference(objkind, name)
2.175 l = self.structures[key] = [None] * len(attrnames)
2.176 +
2.177 for attrname in attrnames:
2.178 position = attr_locations[attrname]
2.179 if position >= len(l):
2.180 l.extend([None] * (position - len(l) + 1))
2.181 l[position] = attrname
2.182
2.183 + # Test the structure against any existing attributes.
2.184 +
2.185 + if self.existing_structures:
2.186 + if self.existing_structures.has_key(key) and self.existing_structures[key] != l:
2.187 + self.differing_structures.append(key)
2.188 +
2.189 def _position_attributes(self, d, l):
2.190
2.191 """
2.192 @@ -756,6 +826,12 @@
2.193
2.194 l[position] = (argname, pos + 1)
2.195
2.196 + # Test the structure against any existing parameters.
2.197 +
2.198 + if self.existing_parameters:
2.199 + if self.existing_parameters.has_key(name) and self.existing_parameters[name] != l:
2.200 + self.differing_parameters.append(name)
2.201 +
2.202 def populate_tables(self):
2.203
2.204 """
2.205 @@ -1055,9 +1131,6 @@
2.206 if new:
2.207 base = new
2.208 allocated_attrnames.add(attrname)
2.209 - else:
2.210 - # NOTE: Signal an error or perform output reset.
2.211 - print "Attribute", attrname, "must be moved."
2.212
2.213 allocated.append(base)
2.214