# HG changeset patch # User Paul Boddie # Date 1488057593 -3600 # Node ID b6ce2977f58b8dec5ad018fd6a5db66f5ff9188a # Parent 170ffd3868264b9419adb46f3a6c625bfbf07cb5 Avoided using temporary accessor variables when names are used as accessors. Added a means of communicating the context of an access to the translator so that names can be used as contexts in certain cases instead of using temporary variables. diff -r 170ffd386826 -r b6ce2977f58b optimiser.py --- a/optimiser.py Fri Feb 24 16:13:28 2017 +0100 +++ b/optimiser.py Sat Feb 25 22:19:53 2017 +0100 @@ -360,8 +360,20 @@ if base: original_accessor = base + + # Employ names as contexts unless the context needs testing and + # potentially updating. In such cases, temporary context storage is + # used instead. + + elif name and not (context_test == "test" and + final_method in ("access-invoke", "static-invoke")): + original_accessor = "" # refers to the name + + # Use a generic placeholder representing the access expression in + # the general case. + else: - original_accessor = "" # use a generic placeholder + original_accessor = "" # Prepare for any first attribute access. @@ -385,6 +397,8 @@ # Set the context if already available. + context_var = None + if context == "base": accessor = context_var = (base,) elif context == "original-accessor": @@ -605,6 +619,11 @@ elif final_method not in ("assign", "static-assign", "static-invoke"): emit(accessor) + # Produce an advisory instruction regarding the context. + + if context_var: + emit(("", context_var)) + self.access_instructions[access_location] = instructions self.accessor_kinds[access_location] = accessor_kinds diff -r 170ffd386826 -r b6ce2977f58b results.py --- a/results.py Fri Feb 24 16:13:28 2017 +0100 +++ b/results.py Sat Feb 25 22:19:53 2017 +0100 @@ -42,6 +42,9 @@ def access_location(self): return None + def context_identity(self): + return None + def get_name(self): return None diff -r 170ffd386826 -r b6ce2977f58b translator.py --- a/translator.py Fri Feb 24 16:13:28 2017 +0100 +++ b/translator.py Sat Feb 25 22:19:53 2017 +0100 @@ -22,7 +22,7 @@ from common import CommonModule, CommonOutput, InstructionSequence, \ first, get_builtin_class, init_item, is_newer, \ predefined_constants -from encoders import encode_access_instruction, \ +from encoders import encode_access_instruction, encode_access_instruction_arg, \ encode_function_pointer, encode_literal_constant, \ encode_literal_instantiator, encode_instantiator_pointer, \ encode_instructions, \ @@ -205,10 +205,11 @@ "A translation result for an attribute access." - def __init__(self, instructions, refs, location): + def __init__(self, instructions, refs, location, context_identity): InstructionSequence.__init__(self, instructions) self.refs = refs self.location = location + self.context_identity = context_identity def references(self): return self.refs @@ -216,6 +217,9 @@ def access_location(self): return self.location + def context(self): + return self.context_identity + def get_origin(self): return self.refs and len(self.refs) == 1 and first(self.refs).get_origin() @@ -227,6 +231,9 @@ return True return False + def __nonzero__(self): + return bool(self.instructions) + def __str__(self): return encode_instructions(self.instructions) @@ -751,6 +758,7 @@ subs = { "" : attr_expr, + "" : "%s.value" % attr_expr, "" : self.in_assignment, } @@ -764,11 +772,22 @@ # invocation. context_index = self.function_target - 1 + context_identity = None # Obtain encoded versions of each instruction, accumulating temporary # variables. for instruction in self.optimiser.access_instructions[location]: + + # Intercept a special instruction identifying the context. + + if instruction[0] == "": + context_identity, _substituted = encode_access_instruction_arg(instruction[1], subs, instruction[0], context_index) + continue + + # Collect the encoded instruction, noting any temporary variables + # required by it. + encoded, _substituted = encode_access_instruction(instruction, subs, context_index) output.append(encoded) substituted.update(_substituted) @@ -780,7 +799,7 @@ self.record_temp(self.temp_subs[sub]) del self.attrs[0] - return AttrResult(output, refs, location) + return AttrResult(output, refs, location, context_identity) def init_substitutions(self): @@ -1225,6 +1244,7 @@ context_required = True have_access_context = isinstance(expr, AttrResult) + context_identity = have_access_context and expr.context() parameters = None # Obtain details of the callable and of its parameters. @@ -1296,8 +1316,9 @@ if context_required: if have_access_context: - self.record_temp("__tmp_contexts") - args = ["(__attr) {.value=__tmp_contexts[%d]}" % self.function_target] + if context_identity.startswith("__tmp_contexts"): + self.record_temp("__tmp_contexts") + args = ["(__attr) {.value=%s}" % context_identity] else: self.record_temp("__tmp_targets") args = ["__CONTEXT_AS_VALUE(__tmp_targets[%d])" % self.function_target] @@ -1398,7 +1419,8 @@ if not target or context_required: if target: - stages.append(str(expr)) + if expr: + stages.append(str(expr)) else: self.record_temp("__tmp_targets") stages.append("__tmp_targets[%d] = %s" % (self.function_target, expr)) @@ -1415,9 +1437,10 @@ if context_required: if have_access_context: - self.record_temp("__tmp_contexts") - stages.append("__get_function(__tmp_contexts[%d], __tmp_targets[%d])" % ( - self.function_target, self.function_target)) + if context_identity.startswith("__tmp_contexts"): + self.record_temp("__tmp_contexts") + stages.append("__get_function(%s, __tmp_targets[%d])" % ( + context_identity, self.function_target)) else: stages.append("__get_function(__CONTEXT_AS_VALUE(__tmp_targets[%d]).value, __tmp_targets[%d])" % ( self.function_target, self.function_target))