1.1 --- a/optimiser.py Fri Feb 24 16:13:28 2017 +0100
1.2 +++ b/optimiser.py Sat Feb 25 22:19:53 2017 +0100
1.3 @@ -360,8 +360,20 @@
1.4
1.5 if base:
1.6 original_accessor = base
1.7 +
1.8 + # Employ names as contexts unless the context needs testing and
1.9 + # potentially updating. In such cases, temporary context storage is
1.10 + # used instead.
1.11 +
1.12 + elif name and not (context_test == "test" and
1.13 + final_method in ("access-invoke", "static-invoke")):
1.14 + original_accessor = "<name>" # refers to the name
1.15 +
1.16 + # Use a generic placeholder representing the access expression in
1.17 + # the general case.
1.18 +
1.19 else:
1.20 - original_accessor = "<expr>" # use a generic placeholder
1.21 + original_accessor = "<expr>"
1.22
1.23 # Prepare for any first attribute access.
1.24
1.25 @@ -385,6 +397,8 @@
1.26
1.27 # Set the context if already available.
1.28
1.29 + context_var = None
1.30 +
1.31 if context == "base":
1.32 accessor = context_var = (base,)
1.33 elif context == "original-accessor":
1.34 @@ -605,6 +619,11 @@
1.35 elif final_method not in ("assign", "static-assign", "static-invoke"):
1.36 emit(accessor)
1.37
1.38 + # Produce an advisory instruction regarding the context.
1.39 +
1.40 + if context_var:
1.41 + emit(("<context_identity>", context_var))
1.42 +
1.43 self.access_instructions[access_location] = instructions
1.44 self.accessor_kinds[access_location] = accessor_kinds
1.45
3.1 --- a/translator.py Fri Feb 24 16:13:28 2017 +0100
3.2 +++ b/translator.py Sat Feb 25 22:19:53 2017 +0100
3.3 @@ -22,7 +22,7 @@
3.4 from common import CommonModule, CommonOutput, InstructionSequence, \
3.5 first, get_builtin_class, init_item, is_newer, \
3.6 predefined_constants
3.7 -from encoders import encode_access_instruction, \
3.8 +from encoders import encode_access_instruction, encode_access_instruction_arg, \
3.9 encode_function_pointer, encode_literal_constant, \
3.10 encode_literal_instantiator, encode_instantiator_pointer, \
3.11 encode_instructions, \
3.12 @@ -205,10 +205,11 @@
3.13
3.14 "A translation result for an attribute access."
3.15
3.16 - def __init__(self, instructions, refs, location):
3.17 + def __init__(self, instructions, refs, location, context_identity):
3.18 InstructionSequence.__init__(self, instructions)
3.19 self.refs = refs
3.20 self.location = location
3.21 + self.context_identity = context_identity
3.22
3.23 def references(self):
3.24 return self.refs
3.25 @@ -216,6 +217,9 @@
3.26 def access_location(self):
3.27 return self.location
3.28
3.29 + def context(self):
3.30 + return self.context_identity
3.31 +
3.32 def get_origin(self):
3.33 return self.refs and len(self.refs) == 1 and first(self.refs).get_origin()
3.34
3.35 @@ -227,6 +231,9 @@
3.36 return True
3.37 return False
3.38
3.39 + def __nonzero__(self):
3.40 + return bool(self.instructions)
3.41 +
3.42 def __str__(self):
3.43 return encode_instructions(self.instructions)
3.44
3.45 @@ -751,6 +758,7 @@
3.46
3.47 subs = {
3.48 "<expr>" : attr_expr,
3.49 + "<name>" : "%s.value" % attr_expr,
3.50 "<assexpr>" : self.in_assignment,
3.51 }
3.52
3.53 @@ -764,11 +772,22 @@
3.54 # invocation.
3.55
3.56 context_index = self.function_target - 1
3.57 + context_identity = None
3.58
3.59 # Obtain encoded versions of each instruction, accumulating temporary
3.60 # variables.
3.61
3.62 for instruction in self.optimiser.access_instructions[location]:
3.63 +
3.64 + # Intercept a special instruction identifying the context.
3.65 +
3.66 + if instruction[0] == "<context_identity>":
3.67 + context_identity, _substituted = encode_access_instruction_arg(instruction[1], subs, instruction[0], context_index)
3.68 + continue
3.69 +
3.70 + # Collect the encoded instruction, noting any temporary variables
3.71 + # required by it.
3.72 +
3.73 encoded, _substituted = encode_access_instruction(instruction, subs, context_index)
3.74 output.append(encoded)
3.75 substituted.update(_substituted)
3.76 @@ -780,7 +799,7 @@
3.77 self.record_temp(self.temp_subs[sub])
3.78
3.79 del self.attrs[0]
3.80 - return AttrResult(output, refs, location)
3.81 + return AttrResult(output, refs, location, context_identity)
3.82
3.83 def init_substitutions(self):
3.84
3.85 @@ -1225,6 +1244,7 @@
3.86
3.87 context_required = True
3.88 have_access_context = isinstance(expr, AttrResult)
3.89 + context_identity = have_access_context and expr.context()
3.90 parameters = None
3.91
3.92 # Obtain details of the callable and of its parameters.
3.93 @@ -1296,8 +1316,9 @@
3.94
3.95 if context_required:
3.96 if have_access_context:
3.97 - self.record_temp("__tmp_contexts")
3.98 - args = ["(__attr) {.value=__tmp_contexts[%d]}" % self.function_target]
3.99 + if context_identity.startswith("__tmp_contexts"):
3.100 + self.record_temp("__tmp_contexts")
3.101 + args = ["(__attr) {.value=%s}" % context_identity]
3.102 else:
3.103 self.record_temp("__tmp_targets")
3.104 args = ["__CONTEXT_AS_VALUE(__tmp_targets[%d])" % self.function_target]
3.105 @@ -1398,7 +1419,8 @@
3.106
3.107 if not target or context_required:
3.108 if target:
3.109 - stages.append(str(expr))
3.110 + if expr:
3.111 + stages.append(str(expr))
3.112 else:
3.113 self.record_temp("__tmp_targets")
3.114 stages.append("__tmp_targets[%d] = %s" % (self.function_target, expr))
3.115 @@ -1415,9 +1437,10 @@
3.116
3.117 if context_required:
3.118 if have_access_context:
3.119 - self.record_temp("__tmp_contexts")
3.120 - stages.append("__get_function(__tmp_contexts[%d], __tmp_targets[%d])" % (
3.121 - self.function_target, self.function_target))
3.122 + if context_identity.startswith("__tmp_contexts"):
3.123 + self.record_temp("__tmp_contexts")
3.124 + stages.append("__get_function(%s, __tmp_targets[%d])" % (
3.125 + context_identity, self.function_target))
3.126 else:
3.127 stages.append("__get_function(__CONTEXT_AS_VALUE(__tmp_targets[%d]).value, __tmp_targets[%d])" % (
3.128 self.function_target, self.function_target))