2.1 --- a/optimiser.py Mon Feb 13 21:49:59 2017 +0100
2.2 +++ b/optimiser.py Tue Feb 14 00:17:39 2017 +0100
2.3 @@ -371,7 +371,7 @@
2.4 # Perform the first access explicitly if at least one operation
2.5 # requires it.
2.6
2.7 - access_first_attribute = final_method in ("access", "assign") or traversed or attrnames
2.8 + access_first_attribute = final_method in ("access", "access-invoke", "assign") or traversed or attrnames
2.9
2.10 # Determine whether the first access involves assignment.
2.11
2.12 @@ -388,8 +388,12 @@
2.13 # Prevent re-evaluation of any dynamic expression by storing it.
2.14
2.15 if original_accessor == "<expr>":
2.16 - emit((set_accessor, original_accessor))
2.17 - accessor = context_var = (stored_accessor,)
2.18 + if final_method in ("access-invoke", "static-invoke"):
2.19 + emit(("<set_context>", original_accessor))
2.20 + accessor = context_var = ("<context>",)
2.21 + else:
2.22 + emit((set_accessor, original_accessor))
2.23 + accessor = context_var = (stored_accessor,)
2.24 else:
2.25 accessor = context_var = (original_accessor,)
2.26
2.27 @@ -462,12 +466,12 @@
2.28 # Set the context, if appropriate.
2.29
2.30 if remaining == 1 and final_method != "assign" and context == "final-accessor":
2.31 - emit(("__set_context", accessor))
2.32 + emit(("<set_context>", accessor))
2.33 accessor = context_var = "<context>"
2.34
2.35 # Perform the access only if not achieved directly.
2.36
2.37 - if remaining > 1 or final_method in ("access", "assign"):
2.38 + if remaining > 1 or final_method in ("access", "access-invoke", "assign"):
2.39
2.40 if traversal_mode == "class":
2.41 if assigning:
2.42 @@ -489,12 +493,12 @@
2.43 # Set the context, if appropriate.
2.44
2.45 if remaining == 1 and final_method != "assign" and context == "final-accessor":
2.46 - emit(("__set_context", accessor))
2.47 + emit(("<set_context>", accessor))
2.48 accessor = context_var = "<context>"
2.49
2.50 # Perform the access only if not achieved directly.
2.51
2.52 - if remaining > 1 or final_method in ("access", "assign"):
2.53 + if remaining > 1 or final_method in ("access", "access-invoke", "assign"):
2.54
2.55 if assigning:
2.56 emit(("__check_and_store_via_any", accessor, attrname, "<assexpr>"))
2.57 @@ -505,10 +509,14 @@
2.58
2.59 # Define or emit the means of accessing the actual target.
2.60
2.61 + # Assignments to known attributes.
2.62 +
2.63 if final_method == "static-assign":
2.64 parent, attrname = origin.rsplit(".", 1)
2.65 emit(("__store_via_object", parent, attrname, "<assexpr>"))
2.66
2.67 + # Invoked attributes employ a separate context.
2.68 +
2.69 elif final_method in ("static", "static-invoke"):
2.70 accessor = ("__load_static_ignore", origin)
2.71
2.72 @@ -521,10 +529,19 @@
2.73 emit(("__test_context", context_var, accessor))
2.74
2.75 elif context_test == "replace":
2.76 - if final_method in ("static", "static-invoke"):
2.77 +
2.78 + # Produce an object with updated context.
2.79 +
2.80 + if final_method == "static":
2.81 emit(("__load_static_replace", context_var, origin))
2.82 +
2.83 + # Only update any context if no separate context is used.
2.84 +
2.85 + elif final_method not in ("access-invoke", "static-invoke"):
2.86 + emit(("__update_context", context_var, accessor))
2.87 +
2.88 else:
2.89 - emit(("__update_context", context_var, accessor))
2.90 + emit(accessor)
2.91
2.92 elif final_method not in ("assign", "static-assign"):
2.93 emit(accessor)
3.1 --- a/translator.py Mon Feb 13 21:49:59 2017 +0100
3.2 +++ b/translator.py Tue Feb 14 00:17:39 2017 +0100
3.3 @@ -740,6 +740,7 @@
3.4
3.5 temp_subs = {
3.6 "<context>" : "__tmp_context",
3.7 + "<set_context>" : "__tmp_context",
3.8 "<accessor>" : "__tmp_value",
3.9 "<target_accessor>" : "__tmp_target_value",
3.10 "<set_accessor>" : "__tmp_value",
3.11 @@ -747,6 +748,7 @@
3.12 }
3.13
3.14 op_subs = {
3.15 + "<set_context>" : "__set_context",
3.16 "<set_accessor>" : "__set_accessor",
3.17 "<set_target_accessor>" : "__set_target_accessor",
3.18 }
3.19 @@ -1165,6 +1167,7 @@
3.20 # Invocation requirements.
3.21
3.22 context_required = True
3.23 + have_access_context = isinstance(expr, AttrResult)
3.24 parameters = None
3.25
3.26 # Obtain details of the callable and of its parameters.
3.27 @@ -1235,8 +1238,11 @@
3.28 # set to null.
3.29
3.30 if context_required:
3.31 - self.record_temp("__tmp_targets")
3.32 - args = ["__CONTEXT_AS_VALUE(__tmp_targets[%d])" % self.function_target]
3.33 + if have_access_context:
3.34 + args = ["(__attr) {.value=__tmp_context}"]
3.35 + else:
3.36 + self.record_temp("__tmp_targets")
3.37 + args = ["__CONTEXT_AS_VALUE(__tmp_targets[%d])" % self.function_target]
3.38 else:
3.39 args = ["__NULL"]
3.40
3.41 @@ -1347,8 +1353,12 @@
3.42 self.record_temp("__tmp_targets")
3.43
3.44 if context_required:
3.45 - stages.append("__get_function(__CONTEXT_AS_VALUE(__tmp_targets[%d]).value, __tmp_targets[%d])" % (
3.46 - self.function_target, self.function_target))
3.47 + if have_access_context:
3.48 + stages.append("__get_function(__tmp_context, __tmp_targets[%d])" % (
3.49 + self.function_target))
3.50 + else:
3.51 + stages.append("__get_function(__CONTEXT_AS_VALUE(__tmp_targets[%d]).value, __tmp_targets[%d])" % (
3.52 + self.function_target, self.function_target))
3.53 else:
3.54 stages.append("__load_via_object(__tmp_targets[%d].value, %s).fn" % (
3.55 self.function_target, encode_symbol("pos", "__fn__")))