# HG changeset patch # User Paul Boddie # Date 1476462854 -7200 # Node ID 2219668ae7d93e477f7c5b353a03f5e952bd447f # Parent a0f513d3a7b1e85f718dfdb16ff44cb788d0cc11 Introduced access mode information for unambiguously-traversed attributes so that the appropriate instruction can be generated. Removed the generation of augmented attribute access plans and the computation of general attribute position ambiguity, since the information will not be used: in cases where ambiguity might need to be determined, attributes must be checked to determine their exact nature even if unambiguous. diff -r a0f513d3a7b1 -r 2219668ae7d9 deducer.py --- a/deducer.py Thu Oct 13 23:27:17 2016 +0200 +++ b/deducer.py Fri Oct 14 18:34:14 2016 +0200 @@ -399,13 +399,14 @@ locations.sort() for location in locations: - name, test, test_type, base, traversed, attrnames, context, \ + name, test, test_type, base, traversed, traversal_modes, attrnames, context, \ first_method, final_method, attr = self.access_plans[location] print >>f_attrs, encode_access_location(location), \ name, test, test_type or "{}", \ base or "{}", \ ".".join(traversed) or "{}", \ + ".".join(traversal_modes) or "{}", \ ".".join(attrnames) or "{}", \ context, first_method, final_method, attr or "{}" @@ -1854,13 +1855,18 @@ dynamic_base = ref.get_origin() traversed = [] + traversal_modes = [] + provider_kind = first(provider_kinds) # Traverse remaining attributes. while len(attrs) == 1: attr = first(attrs) + accessor_kind = attr.get_kind() traversed.append(attrname) + traversal_modes.append(accessor_kind == provider_kind and "object" or "class") + del remaining[0] if not remaining: @@ -1871,11 +1877,13 @@ if attr.static(): base = attr.get_origin() traversed = [] + traversal_modes = [] # Get the next attribute. attrname = remaining[0] attrs = self.importer.get_attributes(attr, attrname) + provider_kind = self.importer.get_attribute_provider(attr, attrname) # Where many attributes are suggested, no single attribute identity can # be loaded. @@ -1916,6 +1924,6 @@ context = len(traversed or remaining) == 1 and (base and "base" or "original-accessor") or "final-accessor" - return name, test, test_type, base, traversed, remaining, context, first_method, final_method, origin + return name, test, test_type, base, traversed, traversal_modes, remaining, context, first_method, final_method, origin # vim: tabstop=4 expandtab shiftwidth=4 diff -r a0f513d3a7b1 -r 2219668ae7d9 importer.py --- a/importer.py Thu Oct 13 23:27:17 2016 +0200 +++ b/importer.py Fri Oct 14 18:34:14 2016 +0200 @@ -249,6 +249,35 @@ else: return None + # Convenience methods for deducing which kind of object provided an + # attribute. + + def get_attribute_provider(self, ref, attrname): + + """ + Return the kind of provider of the attribute accessed via 'ref' using + 'attrname'. + """ + + kind = ref.get_kind() + + if kind in ["", ""]: + return kind + else: + return self.get_instance_attribute_provider(ref.get_origin(), attrname) + + def get_instance_attribute_provider(self, object_type, attrname): + + """ + Return the kind of provider of the attribute accessed via an instance of + 'object_type' using 'attrname'. + """ + + if self.get_class_attribute(object_type, attrname): + return "" + else: + return "" + # Module management. def queue_module(self, name, accessor, required=False): diff -r a0f513d3a7b1 -r 2219668ae7d9 optimiser.py --- a/optimiser.py Thu Oct 13 23:27:17 2016 +0200 +++ b/optimiser.py Fri Oct 14 18:34:14 2016 +0200 @@ -82,7 +82,6 @@ self.position_parameters() self.populate_tables() self.populate_constants() - self.refine_access_plans() self.initialise_access_instructions() def to_output(self): @@ -113,6 +112,7 @@ location " " name " " test " " test type " " base " " traversed attributes " " traversed attribute ambiguity + " " traversal access modes " " attributes to traverse " " attribute ambiguity " " context " " access method " " static attribute @@ -120,6 +120,9 @@ qualified name of scope "." local name ":" name version + Traversal access modes are either "class" (obtain accessor class to + access attribute) or "object" (obtain attribute directly from accessor). + ---- The structures are presented as a table in the following format: @@ -195,28 +198,6 @@ finally: f.close() - f = open(join(self.output, "attribute_plans"), "w") - try: - access_plans = self.access_plans.items() - access_plans.sort() - - for location, (name, test, test_type, base, - traversed, traversed_ambiguity, - attrnames, attrnames_ambiguity, context, - first_method, final_method, attr) in access_plans: - - print >>f, encode_access_location(location), \ - name, test, test_type or "{}", \ - base or "{}", \ - ".".join(traversed) or "{}", \ - ".".join(map(str, traversed_ambiguity)) or "{}", \ - ".".join(map(str, attrnames_ambiguity)) or "{}", \ - ".".join(attrnames) or "{}", \ - context, first_method, final_method, attr or "{}" - - finally: - f.close() - f = open(join(self.output, "instruction_plans"), "w") try: access_instructions = self.access_instructions.items() @@ -355,25 +336,6 @@ l.extend([None] * (position - len(l) + 1)) l[position] = attrname - def refine_access_plans(self): - - "Augment deduced access plans with attribute position information." - - for access_location, access_plan in self.deducer.access_plans.items(): - - # Obtain the access details. - - name, test, test_type, base, traversed, attrnames, \ - context, first_method, final_method, origin = access_plan - - traversed_ambiguity = self.get_ambiguity_for_attributes(traversed) - attrnames_ambiguity = self.get_ambiguity_for_attributes(attrnames) - - self.access_plans[access_location] = \ - name, test, test_type, base, traversed, traversed_ambiguity, \ - attrnames, attrnames_ambiguity, context, \ - first_method, final_method, origin - def initialise_access_instructions(self): "Expand access plans into instruction sequences." @@ -382,9 +344,8 @@ # Obtain the access details. - name, test, test_type, base, traversed, traversed_ambiguity, \ - attrnames, attrnames_ambiguity, context, \ - first_method, final_method, origin = access_plan + name, test, test_type, base, traversed, traversal_modes, \ + attrnames, context, first_method, final_method, origin = access_plan instructions = [] emit = instructions.append @@ -448,14 +409,14 @@ elif first_method == "check-object": emit(("set_accessor", ("check_and_load_via_object", accessor, attrname))) elif first_method == "check-object-class": - emit(("set_accessor", ("get_class_check_and_load", accessor, attrname))) + emit(("set_accessor", ("check_and_load_via_any", accessor, attrname))) # Obtain an accessor. remaining = len(traversed + attrnames) if traversed: - for attrname in traversed: + for attrname, traversal_mode in zip(traversed, traversal_modes): # Set the context, if appropriate. @@ -465,12 +426,15 @@ # Perform the access only if not achieved directly. if remaining > 1 or final_method == "access": - emit(("set_accessor", ("load_unambiguous", "accessor", attrname))) + if traversal_mode == "class": + emit(("set_accessor", ("load_via_class", "accessor", attrname))) + else: + emit(("set_accessor", ("load_via_object", "accessor", attrname))) remaining -= 1 if attrnames: - for attrname, ambiguity in zip(attrnames, attrnames_ambiguity): + for attrname in attrnames: # Set the context, if appropriate. @@ -480,10 +444,7 @@ # Perform the access only if not achieved directly. if remaining > 1 or final_method == "access": - if ambiguity == 1: - emit(("set_accessor", ("load_unambiguous", "accessor", attrname))) - else: - emit(("set_accessor", ("load_ambiguous", "accessor", attrname))) + emit(("set_accessor", ("check_and_load_via_any", "accessor", attrname))) remaining -= 1