1.1 --- a/optimiser.py Wed Mar 01 17:17:27 2017 +0100
1.2 +++ b/optimiser.py Thu Mar 02 01:30:39 2017 +0100
1.3 @@ -20,14 +20,14 @@
1.4 """
1.5
1.6 from common import add_counter_item, get_attrname_from_location, init_item, \
1.7 - sorted_output
1.8 + sorted_output, CommonOutput
1.9 from encoders import digest, encode_access_location, encode_instruction, get_kinds
1.10 from errors import OptimiseError
1.11 from os.path import exists, join
1.12 from os import makedirs
1.13 -from referencing import Reference
1.14 +from referencing import decode_reference, Reference
1.15
1.16 -class Optimiser:
1.17 +class Optimiser(CommonOutput):
1.18
1.19 "Optimise objects in a program."
1.20
1.21 @@ -43,23 +43,35 @@
1.22 self.deducer = deducer
1.23 self.output = output
1.24
1.25 + # Detection of differences between any existing structure or signature
1.26 + # information and the generated information.
1.27 +
1.28 + self.differing_structures = []
1.29 + self.differing_parameters = []
1.30 +
1.31 # Locations/offsets of attributes in objects.
1.32
1.33 self.locations = None
1.34 + self.existing_locations = None
1.35 +
1.36 self.attr_locations = None
1.37 - self.all_attrnames = None
1.38
1.39 - self.existing_locations = []
1.40 - self.existing_attrnames = []
1.41 + # Attribute code assignments.
1.42 +
1.43 + self.all_attrnames = None
1.44 + self.existing_attrnames = None
1.45
1.46 # Locations of parameters in parameter tables.
1.47
1.48 self.arg_locations = None
1.49 + self.existing_arg_locations = None
1.50 +
1.51 self.param_locations = None
1.52 - self.all_paramnames = None
1.53
1.54 - self.existing_arg_locations = []
1.55 - self.existing_paramnames = []
1.56 + # Parameter code assignments.
1.57 +
1.58 + self.all_paramnames = None
1.59 + self.existing_paramnames = None
1.60
1.61 # Specific attribute access information.
1.62
1.63 @@ -69,11 +81,13 @@
1.64 # Object structure information.
1.65
1.66 self.structures = {}
1.67 + self.existing_structures = None
1.68 self.attr_table = {}
1.69
1.70 # Parameter list information.
1.71
1.72 self.parameters = {}
1.73 + self.existing_parameters = None
1.74 self.param_table = {}
1.75
1.76 # Constant literal information.
1.77 @@ -96,14 +110,37 @@
1.78 self.populate_constants()
1.79 self.initialise_access_instructions()
1.80
1.81 + def need_reset(self):
1.82 +
1.83 + """
1.84 + Return whether attribute or parameter information has changed, requiring
1.85 + the reset/recompilation of all source files.
1.86 + """
1.87 +
1.88 + return self.differing_structures or self.differing_parameters
1.89 +
1.90 def from_output(self):
1.91
1.92 "Read input files that influence optimisation."
1.93
1.94 - self.read_locations("locations", self.existing_locations, self._line_to_list, list)
1.95 - self.read_locations("parameter_locations", self.existing_arg_locations, self._line_to_list, list)
1.96 - self.read_locations("attrnames", self.existing_attrnames, lambda x: x, lambda x: None)
1.97 - self.read_locations("paramnames", self.existing_paramnames, lambda x: x, lambda x: None)
1.98 + # Remove any output for a different program.
1.99 +
1.100 + self.check_output()
1.101 +
1.102 + # Existing attribute and parameter positioning information.
1.103 +
1.104 + self.existing_locations = self.read_locations("locations", self._line_to_list, list)
1.105 + self.existing_arg_locations = self.read_locations("parameter_locations", self._line_to_list, list)
1.106 +
1.107 + # Existing attribute and parameter code information.
1.108 +
1.109 + self.existing_attrnames = self.read_locations("attrnames", lambda x: x, lambda x: None)
1.110 + self.existing_paramnames = self.read_locations("paramnames", lambda x: x, lambda x: None)
1.111 +
1.112 + # Existing structure and signature information.
1.113 +
1.114 + self.existing_structures = dict(self.read_locations("structures", self._line_to_structure_pairs, list))
1.115 + self.existing_parameters = dict(self.read_locations("parameters", self._line_to_signature_pairs, list))
1.116
1.117 def _line_to_list(self, line):
1.118
1.119 @@ -111,15 +148,39 @@
1.120
1.121 return line.split(", ")
1.122
1.123 - def read_locations(self, filename, collection, decode, empty):
1.124 + def _line_to_signature_pairs(self, line):
1.125 +
1.126 + "Convert comma-separated values in 'line' to a list of pairs of values."
1.127 +
1.128 + l = []
1.129 + objpath, line = line.split(" ", 1)
1.130 + for values in line.split(", "):
1.131 + if values != "-":
1.132 + name, pos = values.split(":")
1.133 + l.append((name, int(pos)))
1.134 + else:
1.135 + l.append(None)
1.136 + return (objpath, l)
1.137 +
1.138 + def _line_to_structure_pairs(self, line):
1.139 +
1.140 + "Convert comma-separated values in 'line' to a list of pairs of values."
1.141 +
1.142 + l = []
1.143 + ref, line = line.split(" ", 1)
1.144 + values = map(lambda x: x != '-' and x or None, line.split(", "))
1.145 + return (decode_reference(ref), values)
1.146 +
1.147 + def read_locations(self, filename, decode, empty):
1.148
1.149 """
1.150 - Read location details from 'filename' into 'collection', using 'decode'
1.151 - to convert each line and 'empty' to produce an empty result where no
1.152 - data is given on a line.
1.153 + Read location details from 'filename', using 'decode' to convert each
1.154 + line and 'empty' to produce an empty result where no data is given on a
1.155 + line, returning a collection.
1.156 """
1.157
1.158 filename = join(self.output, filename)
1.159 + collection = []
1.160
1.161 if exists(filename):
1.162 f = open(filename)
1.163 @@ -135,6 +196,8 @@
1.164 finally:
1.165 f.close()
1.166
1.167 + return collection
1.168 +
1.169 def to_output(self):
1.170
1.171 "Write the output files using optimisation information."
1.172 @@ -401,12 +464,19 @@
1.173 for (objkind, name), attrnames in self.all_attrs.items():
1.174 key = Reference(objkind, name)
1.175 l = self.structures[key] = [None] * len(attrnames)
1.176 +
1.177 for attrname in attrnames:
1.178 position = attr_locations[attrname]
1.179 if position >= len(l):
1.180 l.extend([None] * (position - len(l) + 1))
1.181 l[position] = attrname
1.182
1.183 + # Test the structure against any existing attributes.
1.184 +
1.185 + if self.existing_structures:
1.186 + if self.existing_structures.has_key(key) and self.existing_structures[key] != l:
1.187 + self.differing_structures.append(key)
1.188 +
1.189 def _position_attributes(self, d, l):
1.190
1.191 """
1.192 @@ -756,6 +826,12 @@
1.193
1.194 l[position] = (argname, pos + 1)
1.195
1.196 + # Test the structure against any existing parameters.
1.197 +
1.198 + if self.existing_parameters:
1.199 + if self.existing_parameters.has_key(name) and self.existing_parameters[name] != l:
1.200 + self.differing_parameters.append(name)
1.201 +
1.202 def populate_tables(self):
1.203
1.204 """
1.205 @@ -1055,9 +1131,6 @@
1.206 if new:
1.207 base = new
1.208 allocated_attrnames.add(attrname)
1.209 - else:
1.210 - # NOTE: Signal an error or perform output reset.
1.211 - print "Attribute", attrname, "must be moved."
1.212
1.213 allocated.append(base)
1.214