1.1 --- a/optimiser.py Wed Oct 12 00:05:08 2016 +0200
1.2 +++ b/optimiser.py Wed Oct 12 18:07:48 2016 +0200
1.3 @@ -21,7 +21,7 @@
1.4
1.5 from common import add_counter_item, get_attrname_from_location, init_item, \
1.6 sorted_output
1.7 -from encoders import encode_access_location, get_kinds
1.8 +from encoders import encode_access_location, encode_instruction, get_kinds
1.9 from os.path import exists, join
1.10 from os import makedirs
1.11 from referencing import Reference
1.12 @@ -57,6 +57,7 @@
1.13 # Specific attribute access information.
1.14
1.15 self.access_plans = {}
1.16 + self.access_instructions = {}
1.17
1.18 # Object structure information.
1.19
1.20 @@ -82,6 +83,7 @@
1.21 self.populate_tables()
1.22 self.populate_constants()
1.23 self.refine_access_plans()
1.24 + self.initialise_access_instructions()
1.25
1.26 def to_output(self):
1.27
1.28 @@ -200,7 +202,8 @@
1.29
1.30 for location, (name, test, test_type, base,
1.31 traversed, traversed_ambiguity,
1.32 - attrnames, attrnames_ambiguity, context, method, attr) in access_plans:
1.33 + attrnames, attrnames_ambiguity, context,
1.34 + first_method, final_method, attr) in access_plans:
1.35
1.36 print >>f, encode_access_location(location), \
1.37 name, test, test_type or "{}", \
1.38 @@ -209,7 +212,21 @@
1.39 ".".join(map(str, traversed_ambiguity)) or "{}", \
1.40 ".".join(map(str, attrnames_ambiguity)) or "{}", \
1.41 ".".join(attrnames) or "{}", \
1.42 - context, method, attr or "{}"
1.43 + context, first_method, final_method, attr or "{}"
1.44 +
1.45 + finally:
1.46 + f.close()
1.47 +
1.48 + f = open(join(self.output, "instruction_plans"), "w")
1.49 + try:
1.50 + access_instructions = self.access_instructions.items()
1.51 + access_instructions.sort()
1.52 +
1.53 + for location, instructions in access_instructions:
1.54 + print >>f, encode_access_location(location), "..."
1.55 + for instruction in instructions:
1.56 + print >>f, encode_instruction(instruction)
1.57 + print >>f
1.58
1.59 finally:
1.60 f.close()
1.61 @@ -347,14 +364,133 @@
1.62 # Obtain the access details.
1.63
1.64 name, test, test_type, base, traversed, attrnames, \
1.65 - context, method, attr = access_plan
1.66 + context, first_method, final_method, origin = access_plan
1.67
1.68 traversed_ambiguity = self.get_ambiguity_for_attributes(traversed)
1.69 attrnames_ambiguity = self.get_ambiguity_for_attributes(attrnames)
1.70
1.71 self.access_plans[access_location] = \
1.72 name, test, test_type, base, traversed, traversed_ambiguity, \
1.73 - attrnames, attrnames_ambiguity, context, method, attr
1.74 + attrnames, attrnames_ambiguity, context, \
1.75 + first_method, final_method, origin
1.76 +
1.77 + def initialise_access_instructions(self):
1.78 +
1.79 + "Expand access plans into instruction sequences."
1.80 +
1.81 + for access_location, access_plan in self.access_plans.items():
1.82 +
1.83 + # Obtain the access details.
1.84 +
1.85 + name, test, test_type, base, traversed, traversed_ambiguity, \
1.86 + attrnames, attrnames_ambiguity, context, \
1.87 + first_method, final_method, origin = access_plan
1.88 +
1.89 + instructions = []
1.90 + emit = instructions.append
1.91 +
1.92 + if base:
1.93 + original_accessor = base
1.94 + else:
1.95 + original_accessor = name
1.96 +
1.97 + # Prepare for any first attribute access.
1.98 +
1.99 + if traversed:
1.100 + attrname = traversed[0]
1.101 + del traversed[0]
1.102 + elif attrnames:
1.103 + attrname = attrnames[0]
1.104 + del attrnames[0]
1.105 +
1.106 + access_first_attribute = final_method == "access" or traversed or attrnames
1.107 +
1.108 + if context == "final-accessor" or access_first_attribute:
1.109 + emit(("set_accessor", original_accessor))
1.110 +
1.111 + # Set the context if already available.
1.112 +
1.113 + if context == "original-accessor":
1.114 + emit(("set_context", original_accessor))
1.115 + elif context == "base":
1.116 + emit(("set_context", base))
1.117 +
1.118 + # Apply any test.
1.119 +
1.120 + if test_type == "specific-type":
1.121 + emit(("test_specific_type", accessor, test_type))
1.122 + elif test_type == "specific-instance":
1.123 + emit(("test_specific_instance", accessor, test_type))
1.124 + elif test_type == "specific-object":
1.125 + emit(("test_specific_object", accessor, test_type))
1.126 + elif test_type == "common-type":
1.127 + emit(("test_common_type", accessor, test_type))
1.128 + elif test_type == "common-instance":
1.129 + emit(("test_common_instance", accessor, test_type))
1.130 + elif test_type == "common-object":
1.131 + emit(("test_common_object", accessor, test_type))
1.132 +
1.133 + # Perform the first or final access.
1.134 + # The access only needs performing if the resulting accessor is used.
1.135 +
1.136 + if access_first_attribute:
1.137 +
1.138 + if first_method == "relative-class":
1.139 + emit(("set_accessor", ("load_via_class", "accessor", "attrname")))
1.140 + elif first_method == "relative-object":
1.141 + emit(("set_accessor", ("load_via_object", "accessor", "attrname")))
1.142 + elif first_method == "relative-object-class":
1.143 + emit(("set_accessor", ("get_class_and_load", "accessor", "attrname")))
1.144 + elif first_method == "check-class":
1.145 + emit(("set_accessor", ("check_and_load_via_class", "accessor", "attrname")))
1.146 + elif first_method == "check-object":
1.147 + emit(("set_accessor", ("check_and_load_via_object", "accessor", "attrname")))
1.148 + elif first_method == "check-object-class":
1.149 + emit(("set_accessor", ("get_class_check_and_load", "accessor", "attrname")))
1.150 +
1.151 + # Obtain an accessor.
1.152 +
1.153 + remaining = len(traversed + attrnames)
1.154 +
1.155 + if traversed:
1.156 + for attrname in traversed:
1.157 +
1.158 + # Set the context, if appropriate.
1.159 +
1.160 + if remaining == 1 and context == "final-accessor":
1.161 + emit(("set_context", "accessor"))
1.162 +
1.163 + # Perform the access only if not achieved directly.
1.164 +
1.165 + if remaining > 1 or final_method == "access":
1.166 + emit(("set_accessor", ("load_unambiguous", "accessor", attrname)))
1.167 +
1.168 + remaining -= 1
1.169 +
1.170 + if attrnames:
1.171 + for attrname, ambiguity in zip(attrnames, attrnames_ambiguity):
1.172 +
1.173 + # Set the context, if appropriate.
1.174 +
1.175 + if remaining == 1 and context == "final-accessor":
1.176 + emit(("set_context", "accessor"))
1.177 +
1.178 + # Perform the access only if not achieved directly.
1.179 +
1.180 + if remaining > 1 or final_method == "access":
1.181 + if ambiguity == 1:
1.182 + emit(("set_accessor", ("load_unambiguous", "accessor", attrname)))
1.183 + else:
1.184 + emit(("set_accessor", ("load_ambiguous", "accessor", attrname)))
1.185 +
1.186 + remaining -= 1
1.187 +
1.188 + if final_method == "assign":
1.189 + emit(("store_member", origin, "<expr>"))
1.190 + elif final_method == "static":
1.191 + emit(("load_static", origin))
1.192 +
1.193 + self.access_instructions[access_location] = instructions
1.194
1.195 def get_ambiguity_for_attributes(self, attrnames):
1.196