1.1 --- a/deducer.py Fri Nov 25 18:36:10 2016 +0100
1.2 +++ b/deducer.py Fri Nov 25 18:36:45 2016 +0100
1.3 @@ -25,7 +25,7 @@
1.4 sorted_output, CommonOutput
1.5 from encoders import encode_attrnames, encode_access_location, \
1.6 encode_constrained, encode_location, encode_usage, \
1.7 - get_kinds, test_for_kinds, test_for_type
1.8 + get_kinds, test_label_for_kind, test_label_for_type
1.9 from errors import DeduceError
1.10 from os.path import join
1.11 from referencing import combine_types, is_single_class_type, separate_types, \
1.12 @@ -260,23 +260,25 @@
1.13 print >>f_warnings, encode_location(location), "; ".join(map(encode_usage, attrnames))
1.14
1.15 guard_test = self.accessor_guard_tests.get(location)
1.16 + if guard_test:
1.17 + guard_test_type, guard_test_arg = guard_test
1.18
1.19 # Write specific type guard details.
1.20
1.21 - if guard_test and guard_test.startswith("specific"):
1.22 - print >>f_guards, encode_location(location), guard_test, \
1.23 - get_kinds(all_types)[0], \
1.24 + if guard_test and guard_test_type == "specific":
1.25 + print >>f_guards, encode_location(location), "-".join(guard_test), \
1.26 + first(get_kinds(all_types)), \
1.27 sorted_output(all_types)
1.28
1.29 # Write common type guard details.
1.30
1.31 - elif guard_test and guard_test.startswith("common"):
1.32 - print >>f_guards, encode_location(location), guard_test, \
1.33 - get_kinds(all_general_types)[0], \
1.34 + elif guard_test and guard_test_type == "common":
1.35 + print >>f_guards, encode_location(location), "-".join(guard_test), \
1.36 + first(get_kinds(all_general_types)), \
1.37 sorted_output(all_general_types)
1.38
1.39 print >>f_type_summary, encode_location(location), encode_constrained(constrained), \
1.40 - guard_test or "unguarded", sorted_output(all_general_types), len(all_types)
1.41 + guard_test and "-".join(guard_test) or "unguarded", sorted_output(all_general_types), len(all_types)
1.42
1.43 finally:
1.44 f_type_summary.close()
1.45 @@ -362,18 +364,18 @@
1.46
1.47 # Write the need to test at run time.
1.48
1.49 - if test_type == "validate":
1.50 - print >>f_tests, encode_access_location(location), test_type
1.51 + if test_type[0] == "validate":
1.52 + print >>f_tests, encode_access_location(location), "-".join(test_type)
1.53
1.54 # Write any type checks for anonymous accesses.
1.55
1.56 elif test_type and self.reference_test_accessor_type.get(location):
1.57 - print >>f_tests, encode_access_location(location), test_type, \
1.58 + print >>f_tests, encode_access_location(location), "-".join(test_type[1:]), \
1.59 sorted_output(all_accessed_attrs), \
1.60 self.reference_test_accessor_type[location]
1.61
1.62 print >>f_attr_summary, encode_access_location(location), encode_constrained(constrained), \
1.63 - test_type or "untested", sorted_output(all_accessed_attrs)
1.64 + test_type and "-".join(test_type) or "untested", sorted_output(all_accessed_attrs)
1.65
1.66 else:
1.67 print >>f_warnings, encode_access_location(location)
1.68 @@ -409,7 +411,8 @@
1.69
1.70 print >>f_attrs, encode_access_location(location), \
1.71 name or "{}", \
1.72 - test, test_type or "{}", \
1.73 + test and "-".join(test) or "{}", \
1.74 + test_type or "{}", \
1.75 base or "{}", \
1.76 ".".join(traversed) or "{}", \
1.77 ".".join(traversal_modes) or "{}", \
1.78 @@ -473,16 +476,16 @@
1.79 # Record specific type guard details.
1.80
1.81 if len(all_types) == 1:
1.82 - self.accessor_guard_tests[location] = test_for_type("specific", first(all_types))
1.83 + self.accessor_guard_tests[location] = ("specific", test_label_for_type(first(all_types)))
1.84 elif is_single_class_type(all_types):
1.85 - self.accessor_guard_tests[location] = "specific-object"
1.86 + self.accessor_guard_tests[location] = ("specific", "object")
1.87
1.88 # Record common type guard details.
1.89
1.90 elif len(all_general_types) == 1:
1.91 - self.accessor_guard_tests[location] = test_for_type("common", first(all_types))
1.92 + self.accessor_guard_tests[location] = ("common", test_label_for_type(first(all_types)))
1.93 elif is_single_class_type(all_general_types):
1.94 - self.accessor_guard_tests[location] = "common-object"
1.95 + self.accessor_guard_tests[location] = ("common", "object")
1.96
1.97 # Otherwise, no convenient guard can be defined.
1.98
1.99 @@ -581,15 +584,15 @@
1.100
1.101 if constrained:
1.102 if single_accessor_type:
1.103 - self.reference_test_types[location] = test_for_type("constrained-specific", first(all_accessor_types))
1.104 + self.reference_test_types[location] = ("constrained", "specific", test_label_for_type(first(all_accessor_types)))
1.105 elif single_accessor_class_type:
1.106 - self.reference_test_types[location] = "constrained-specific-object"
1.107 + self.reference_test_types[location] = ("constrained", "specific", "object")
1.108 elif single_accessor_general_type:
1.109 - self.reference_test_types[location] = test_for_type("constrained-common", first(all_accessor_general_types))
1.110 + self.reference_test_types[location] = ("constrained", "common", test_label_for_type(first(all_accessor_general_types)))
1.111 elif single_accessor_general_class_type:
1.112 - self.reference_test_types[location] = "constrained-common-object"
1.113 + self.reference_test_types[location] = ("constrained", "common", "object")
1.114 else:
1.115 - self.reference_test_types[location] = "constrained-many"
1.116 + self.reference_test_types[location] = ("constrained", "many")
1.117
1.118 # Suitably guarded accesses, where the nature of the
1.119 # accessor can be guaranteed, do not require the attribute
1.120 @@ -598,13 +601,13 @@
1.121
1.122 elif guarded and all_accessed_attrs.issubset(guard_attrs):
1.123 if single_accessor_type:
1.124 - self.reference_test_types[location] = test_for_type("guarded-specific", first(all_accessor_types))
1.125 + self.reference_test_types[location] = ("guarded", "specific", test_label_for_type(first(all_accessor_types)))
1.126 elif single_accessor_class_type:
1.127 - self.reference_test_types[location] = "guarded-specific-object"
1.128 + self.reference_test_types[location] = ("guarded", "specific", "object")
1.129 elif single_accessor_general_type:
1.130 - self.reference_test_types[location] = test_for_type("guarded-common", first(all_accessor_general_types))
1.131 + self.reference_test_types[location] = ("guarded", "common", test_label_for_type(first(all_accessor_general_types)))
1.132 elif single_accessor_general_class_type:
1.133 - self.reference_test_types[location] = "guarded-common-object"
1.134 + self.reference_test_types[location] = ("guarded", "common", "object")
1.135
1.136 # Record the need to test the type of anonymous and
1.137 # unconstrained accessors.
1.138 @@ -614,9 +617,9 @@
1.139 if provider != '__builtins__.object':
1.140 all_accessor_kinds = set(get_kinds(all_accessor_types))
1.141 if len(all_accessor_kinds) == 1:
1.142 - test_type = test_for_kinds("specific", all_accessor_kinds)
1.143 + test_type = ("test", "specific", first(all_accessor_kinds))
1.144 else:
1.145 - test_type = "specific-object"
1.146 + test_type = ("test", "specific", "object")
1.147 self.reference_test_types[location] = test_type
1.148 self.reference_test_accessor_type[location] = provider
1.149
1.150 @@ -625,16 +628,16 @@
1.151 if provider != '__builtins__.object':
1.152 all_accessor_kinds = set(get_kinds(all_accessor_general_types))
1.153 if len(all_accessor_kinds) == 1:
1.154 - test_type = test_for_kinds("common", all_accessor_kinds)
1.155 + test_type = ("test", "common", first(all_accessor_kinds))
1.156 else:
1.157 - test_type = "common-object"
1.158 + test_type = ("test", "common", "object")
1.159 self.reference_test_types[location] = test_type
1.160 self.reference_test_accessor_type[location] = provider
1.161
1.162 # Record the need to test the identity of the attribute.
1.163
1.164 else:
1.165 - self.reference_test_types[location] = "validate"
1.166 + self.reference_test_types[location] = ("validate",)
1.167
1.168 def initialise_access_plans(self):
1.169
1.170 @@ -1749,54 +1752,11 @@
1.171
1.172 return attrs
1.173
1.174 - constrained_specific_tests = (
1.175 - "constrained-specific-instance",
1.176 - "constrained-specific-type",
1.177 - "constrained-specific-object",
1.178 - )
1.179 -
1.180 - constrained_common_tests = (
1.181 - "constrained-common-instance",
1.182 - "constrained-common-type",
1.183 - "constrained-common-object",
1.184 - )
1.185 -
1.186 - guarded_specific_tests = (
1.187 - "guarded-specific-instance",
1.188 - "guarded-specific-type",
1.189 - "guarded-specific-object",
1.190 - )
1.191 -
1.192 - guarded_common_tests = (
1.193 - "guarded-common-instance",
1.194 - "guarded-common-type",
1.195 - "guarded-common-object",
1.196 - )
1.197 -
1.198 - specific_tests = (
1.199 - "specific-instance",
1.200 - "specific-type",
1.201 - "specific-object",
1.202 - )
1.203 -
1.204 - common_tests = (
1.205 - "common-instance",
1.206 - "common-type",
1.207 - "common-object",
1.208 - )
1.209 -
1.210 class_tests = (
1.211 - "guarded-specific-type",
1.212 - "guarded-common-type",
1.213 - "specific-type",
1.214 - "common-type",
1.215 - )
1.216 -
1.217 - class_or_instance_tests = (
1.218 - "guarded-specific-object",
1.219 - "guarded-common-object",
1.220 - "specific-object",
1.221 - "common-object",
1.222 + ("guarded", "specific", "type"),
1.223 + ("guarded", "common", "type"),
1.224 + ("test", "specific", "type"),
1.225 + ("test", "common", "type"),
1.226 )
1.227
1.228 def get_access_plan(self, location):
1.229 @@ -1883,22 +1843,22 @@
1.230
1.231 # Usage of previously-generated guard and test details.
1.232
1.233 - elif test in self.constrained_specific_tests:
1.234 + elif test[:2] == ("constrained", "specific"):
1.235 ref = first(accessor_types)
1.236
1.237 - elif test in self.constrained_common_tests:
1.238 + elif test[:2] == ("constrained", "common"):
1.239 ref = first(accessor_general_types)
1.240
1.241 - elif test in self.guarded_specific_tests:
1.242 + elif test[:2] == ("guarded", "specific"):
1.243 ref = first(accessor_types)
1.244
1.245 - elif test in self.guarded_common_tests:
1.246 + elif test[:2] == ("guarded", "common"):
1.247 ref = first(accessor_general_types)
1.248
1.249 # For attribute-based tests, tentatively identify a dynamic base.
1.250 # Such tests allow single or multiple kinds of a type.
1.251
1.252 - elif test in self.common_tests or test in self.specific_tests:
1.253 + elif test[0] == "test" and test[1] in ("common", "specific"):
1.254 dynamic_base = test_type
1.255
1.256 # Static accessors.
6.1 --- a/translator.py Fri Nov 25 18:36:10 2016 +0100
6.2 +++ b/translator.py Fri Nov 25 18:36:45 2016 +0100
6.3 @@ -245,9 +245,10 @@
6.4 self.in_try_finally = False
6.5 self.in_try_except = False
6.6
6.7 - # Attribute access counting.
6.8 + # Attribute access and accessor counting.
6.9
6.10 self.attr_accesses = {}
6.11 + self.attr_accessors = {}
6.12
6.13 def __repr__(self):
6.14 return "TranslatedModule(%r, %r)" % (self.name, self.importer)
6.15 @@ -710,6 +711,34 @@
6.16 init_item(self.attr_accesses[path], access, lambda: 0)
6.17 self.attr_accesses[path][access] += 1
6.18
6.19 + def get_accessor_location(self, name):
6.20 +
6.21 + """
6.22 + Using the current namespace and the given 'name', return the accessor
6.23 + location.
6.24 + """
6.25 +
6.26 + path = self.get_path_for_access()
6.27 +
6.28 + # Get the location used by the deducer and optimiser and find any
6.29 + # recorded accessor.
6.30 +
6.31 + access_number = self.get_accessor_number(path, name)
6.32 + self.update_accessor_number(path, name)
6.33 + return (path, name, None, access_number)
6.34 +
6.35 + def get_accessor_number(self, path, name):
6.36 + if self.attr_accessors.has_key(path) and self.attr_accessors[path].has_key(name):
6.37 + return self.attr_accessors[path][name]
6.38 + else:
6.39 + return 0
6.40 +
6.41 + def update_accessor_number(self, path, name):
6.42 + if name:
6.43 + init_item(self.attr_accessors, path, dict)
6.44 + init_item(self.attr_accessors[path], name, lambda: 0)
6.45 + self.attr_accessors[path][name] += 1
6.46 +
6.47 def process_class_node(self, n):
6.48
6.49 "Process the given class node 'n'."
6.50 @@ -740,6 +769,34 @@
6.51 self.in_conditional = False
6.52 self.function_target = 0
6.53
6.54 + # Process any guards defined for the parameters.
6.55 +
6.56 + for name in self.importer.function_parameters.get(function_name):
6.57 +
6.58 + # Get the accessor details and any guards defined for it.
6.59 +
6.60 + location = self.get_accessor_location(name)
6.61 + test = self.deducer.accessor_guard_tests.get(location)
6.62 + if test:
6.63 + guard, guard_type = test
6.64 +
6.65 + if guard == "specific":
6.66 + ref = first(self.deducer.accessor_all_types[location])
6.67 + argstr = "&%s" % encode_path(ref.get_origin())
6.68 + elif guard == "common":
6.69 + ref = first(self.deducer.accessor_all_general_types[location])
6.70 + typeattr = encode_type_attribute(ref.get_origin())
6.71 + argstr = "%s, %s" % (encode_symbol("pos", typeattr), encode_symbol("code", typeattr))
6.72 + else:
6.73 + continue
6.74 +
6.75 + # Write a test that raises a TypeError upon failure.
6.76 +
6.77 + self.writestmt("if (!__test_%s_%s(%s->value, %s)) __raise_type_error();" % (
6.78 + guard, guard_type, name, argstr))
6.79 +
6.80 + # Produce the body and any additional return statement.
6.81 +
6.82 expr = self.process_structure_node(n.code) or PredefinedConstantRef("None")
6.83 if not isinstance(expr, ReturnRef):
6.84 self.writestmt("return %s;" % expr)