1.1 --- a/deducer.py Wed Oct 12 00:05:08 2016 +0200
1.2 +++ b/deducer.py Wed Oct 12 18:07:48 2016 +0200
1.3 @@ -400,14 +400,14 @@
1.4
1.5 for location in locations:
1.6 name, test, test_type, base, traversed, attrnames, context, \
1.7 - method, attr = self.access_plans[location]
1.8 + first_method, final_method, attr = self.access_plans[location]
1.9
1.10 print >>f_attrs, encode_access_location(location), \
1.11 name, test, test_type or "{}", \
1.12 base or "{}", \
1.13 ".".join(traversed) or "{}", \
1.14 ".".join(attrnames) or "{}", \
1.15 - context, method, attr or "{}"
1.16 + context, first_method, final_method, attr or "{}"
1.17
1.18 finally:
1.19 f_attrs.close()
1.20 @@ -1888,31 +1888,34 @@
1.21 # Identified attribute that must be accessed via its parent.
1.22
1.23 if attr and attr.get_name() and location in self.reference_assignments:
1.24 - method = "assign"; origin = attr.get_name()
1.25 + final_method = "assign"; origin = attr.get_name()
1.26
1.27 # Static, identified attribute.
1.28
1.29 elif attr and attr.static():
1.30 - method = "static"; origin = attr.final()
1.31 + final_method = "static"; origin = attr.final()
1.32 +
1.33 + # All other methods of access involve traversal.
1.34 +
1.35 + else:
1.36 + final_method = "access"; origin = None
1.37
1.38 # First attribute accessed at a known position via the accessor.
1.39
1.40 - elif base or dynamic_base:
1.41 - method = "relative" + (object_relative and "-object" or "") + \
1.42 - (class_relative and "-class" or "")
1.43 - origin = None
1.44 + if base or dynamic_base:
1.45 + first_method = "relative" + (object_relative and "-object" or "") + \
1.46 + (class_relative and "-class" or "")
1.47
1.48 # The fallback case is always run-time testing and access.
1.49
1.50 else:
1.51 - method = "check" + (object_relative and "-object" or "") + \
1.52 - (class_relative and "-class" or "")
1.53 - origin = None
1.54 + first_method = "check" + (object_relative and "-object" or "") + \
1.55 + (class_relative and "-class" or "")
1.56
1.57 # Determine the nature of the context.
1.58
1.59 context = len(traversed or remaining) == 1 and (base and "base" or "original-accessor") or "final-accessor"
1.60
1.61 - return name, test, test_type, base, traversed, remaining, context, method, origin
1.62 + return name, test, test_type, base, traversed, remaining, context, first_method, final_method, origin
1.63
1.64 # vim: tabstop=4 expandtab shiftwidth=4
3.1 --- a/optimiser.py Wed Oct 12 00:05:08 2016 +0200
3.2 +++ b/optimiser.py Wed Oct 12 18:07:48 2016 +0200
3.3 @@ -21,7 +21,7 @@
3.4
3.5 from common import add_counter_item, get_attrname_from_location, init_item, \
3.6 sorted_output
3.7 -from encoders import encode_access_location, get_kinds
3.8 +from encoders import encode_access_location, encode_instruction, get_kinds
3.9 from os.path import exists, join
3.10 from os import makedirs
3.11 from referencing import Reference
3.12 @@ -57,6 +57,7 @@
3.13 # Specific attribute access information.
3.14
3.15 self.access_plans = {}
3.16 + self.access_instructions = {}
3.17
3.18 # Object structure information.
3.19
3.20 @@ -82,6 +83,7 @@
3.21 self.populate_tables()
3.22 self.populate_constants()
3.23 self.refine_access_plans()
3.24 + self.initialise_access_instructions()
3.25
3.26 def to_output(self):
3.27
3.28 @@ -200,7 +202,8 @@
3.29
3.30 for location, (name, test, test_type, base,
3.31 traversed, traversed_ambiguity,
3.32 - attrnames, attrnames_ambiguity, context, method, attr) in access_plans:
3.33 + attrnames, attrnames_ambiguity, context,
3.34 + first_method, final_method, attr) in access_plans:
3.35
3.36 print >>f, encode_access_location(location), \
3.37 name, test, test_type or "{}", \
3.38 @@ -209,7 +212,21 @@
3.39 ".".join(map(str, traversed_ambiguity)) or "{}", \
3.40 ".".join(map(str, attrnames_ambiguity)) or "{}", \
3.41 ".".join(attrnames) or "{}", \
3.42 - context, method, attr or "{}"
3.43 + context, first_method, final_method, attr or "{}"
3.44 +
3.45 + finally:
3.46 + f.close()
3.47 +
3.48 + f = open(join(self.output, "instruction_plans"), "w")
3.49 + try:
3.50 + access_instructions = self.access_instructions.items()
3.51 + access_instructions.sort()
3.52 +
3.53 + for location, instructions in access_instructions:
3.54 + print >>f, encode_access_location(location), "..."
3.55 + for instruction in instructions:
3.56 + print >>f, encode_instruction(instruction)
3.57 + print >>f
3.58
3.59 finally:
3.60 f.close()
3.61 @@ -347,14 +364,133 @@
3.62 # Obtain the access details.
3.63
3.64 name, test, test_type, base, traversed, attrnames, \
3.65 - context, method, attr = access_plan
3.66 + context, first_method, final_method, origin = access_plan
3.67
3.68 traversed_ambiguity = self.get_ambiguity_for_attributes(traversed)
3.69 attrnames_ambiguity = self.get_ambiguity_for_attributes(attrnames)
3.70
3.71 self.access_plans[access_location] = \
3.72 name, test, test_type, base, traversed, traversed_ambiguity, \
3.73 - attrnames, attrnames_ambiguity, context, method, attr
3.74 + attrnames, attrnames_ambiguity, context, \
3.75 + first_method, final_method, origin
3.76 +
3.77 + def initialise_access_instructions(self):
3.78 +
3.79 + "Expand access plans into instruction sequences."
3.80 +
3.81 + for access_location, access_plan in self.access_plans.items():
3.82 +
3.83 + # Obtain the access details.
3.84 +
3.85 + name, test, test_type, base, traversed, traversed_ambiguity, \
3.86 + attrnames, attrnames_ambiguity, context, \
3.87 + first_method, final_method, origin = access_plan
3.88 +
3.89 + instructions = []
3.90 + emit = instructions.append
3.91 +
3.92 + if base:
3.93 + original_accessor = base
3.94 + else:
3.95 + original_accessor = name
3.96 +
3.97 + # Prepare for any first attribute access.
3.98 +
3.99 + if traversed:
3.100 + attrname = traversed[0]
3.101 + del traversed[0]
3.102 + elif attrnames:
3.103 + attrname = attrnames[0]
3.104 + del attrnames[0]
3.105 +
3.106 + access_first_attribute = final_method == "access" or traversed or attrnames
3.107 +
3.108 + if context == "final-accessor" or access_first_attribute:
3.109 + emit(("set_accessor", original_accessor))
3.110 +
3.111 + # Set the context if already available.
3.112 +
3.113 + if context == "original-accessor":
3.114 + emit(("set_context", original_accessor))
3.115 + elif context == "base":
3.116 + emit(("set_context", base))
3.117 +
3.118 + # Apply any test.
3.119 +
3.120 + if test_type == "specific-type":
3.121 + emit(("test_specific_type", accessor, test_type))
3.122 + elif test_type == "specific-instance":
3.123 + emit(("test_specific_instance", accessor, test_type))
3.124 + elif test_type == "specific-object":
3.125 + emit(("test_specific_object", accessor, test_type))
3.126 + elif test_type == "common-type":
3.127 + emit(("test_common_type", accessor, test_type))
3.128 + elif test_type == "common-instance":
3.129 + emit(("test_common_instance", accessor, test_type))
3.130 + elif test_type == "common-object":
3.131 + emit(("test_common_object", accessor, test_type))
3.132 +
3.133 + # Perform the first or final access.
3.134 + # The access only needs performing if the resulting accessor is used.
3.135 +
3.136 + if access_first_attribute:
3.137 +
3.138 + if first_method == "relative-class":
3.139 + emit(("set_accessor", ("load_via_class", "accessor", "attrname")))
3.140 + elif first_method == "relative-object":
3.141 + emit(("set_accessor", ("load_via_object", "accessor", "attrname")))
3.142 + elif first_method == "relative-object-class":
3.143 + emit(("set_accessor", ("get_class_and_load", "accessor", "attrname")))
3.144 + elif first_method == "check-class":
3.145 + emit(("set_accessor", ("check_and_load_via_class", "accessor", "attrname")))
3.146 + elif first_method == "check-object":
3.147 + emit(("set_accessor", ("check_and_load_via_object", "accessor", "attrname")))
3.148 + elif first_method == "check-object-class":
3.149 + emit(("set_accessor", ("get_class_check_and_load", "accessor", "attrname")))
3.150 +
3.151 + # Obtain an accessor.
3.152 +
3.153 + remaining = len(traversed + attrnames)
3.154 +
3.155 + if traversed:
3.156 + for attrname in traversed:
3.157 +
3.158 + # Set the context, if appropriate.
3.159 +
3.160 + if remaining == 1 and context == "final-accessor":
3.161 + emit(("set_context", "accessor"))
3.162 +
3.163 + # Perform the access only if not achieved directly.
3.164 +
3.165 + if remaining > 1 or final_method == "access":
3.166 + emit(("set_accessor", ("load_unambiguous", "accessor", attrname)))
3.167 +
3.168 + remaining -= 1
3.169 +
3.170 + if attrnames:
3.171 + for attrname, ambiguity in zip(attrnames, attrnames_ambiguity):
3.172 +
3.173 + # Set the context, if appropriate.
3.174 +
3.175 + if remaining == 1 and context == "final-accessor":
3.176 + emit(("set_context", "accessor"))
3.177 +
3.178 + # Perform the access only if not achieved directly.
3.179 +
3.180 + if remaining > 1 or final_method == "access":
3.181 + if ambiguity == 1:
3.182 + emit(("set_accessor", ("load_unambiguous", "accessor", attrname)))
3.183 + else:
3.184 + emit(("set_accessor", ("load_ambiguous", "accessor", attrname)))
3.185 +
3.186 + remaining -= 1
3.187 +
3.188 + if final_method == "assign":
3.189 + emit(("store_member", origin, "<expr>"))
3.190 + elif final_method == "static":
3.191 + emit(("load_static", origin))
3.192 +
3.193 + self.access_instructions[access_location] = instructions
3.194
3.195 def get_ambiguity_for_attributes(self, attrnames):
3.196