This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Replace store/load pair with a single new opcode
Type: Stage:
Components: Interpreter Core Versions: Python 2.5
process
Status: closed Resolution: remind
Dependencies: Superseder:
Assigned To: rhettinger Nosy List: loewis, rhettinger
Priority: normal Keywords: patch

Created on 2005-02-20 15:41 by rhettinger, last changed 2022-04-11 14:56 by admin. This issue is now closed.

Files
File name Uploaded Description Edit
dupstore.diff rhettinger, 2005-02-20 15:41 Basic patch with tests
a.py loewis, 2005-02-21 22:37
Messages (6)
msg47831 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2005-02-20 15:41
The folds the two steps into a new opcode.  In the case
of store_name/load_name, it saves one three byte
instruction, a trip around the eval-loop, two stack
mutations, a incref/decref pair, a dictionary lookup,
and an error check (for the lookup).  While it acts
like a dup followed by a store, it is implemented more
simply as a store that doesn’t pop the stack.  The
transformation is broadly applicable and occurs
thousands of times in the standard library and test suite.
msg47832 - (view) Author: Martin v. Löwis (loewis) * (Python committer) Date: 2005-02-20 23:24
Logged In: YES 
user_id=21627

Please add a patch to Doc/lib/libdis.tex. Also, it would be
good if a comment explained why these (all of the peephole
optimizations) can never read over the end of the string.

It appears that this patch introduces a change in semantics
for STORE_NAME if f_locals is not a dictionary - with the
patch, the dictionary-like object will see one less call to
GetItem.
msg47833 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2005-02-21 16:12
Logged In: YES 
user_id=80475

Thanks for looking at the patch.

Added patch to Doc/lib/libdis.tex.

Added a comment and assertion documenting how the pattern
recognizer stays within the string boundaries (it uses
RETURN_VALUE as a guard).

The transformations are invariant with respect to the
preconditions and postconditions (in terms of stack effect
and dictionary state).  They change the how without changing
the what.   In this case, saving the unnecessary dictionary
lookup is the point of the transformation.  The code
generator is free to produce STORE x LOAD x or the
equivalent DUP STORE x.  This is the lead example in Skip's
paper on the subject: 
http://www.foretec.com/python/workshops/1998-11/proceedings/papers/montanaro/montanaro.html

The pattern is generated by code in the form:
  x = f()
  y = x + 1

The postcondition states of x and y remain unchanged by the
transformation.  The other peepholer transforms work the
same way (i.e. the condition jump to conditional jump
simplification results in fewer comparisons because the
results of identical comparisons are expected to be the same).

There is a limit to this.  For instance, x * 2 cannot be
replaced with x + x because it results in a different method
being called.  The multiply call is guaranteed.  This
contrasts with the incidental getitem call in x=f(); y=x+1
where the compiler guarantees the call to f() and the final
states of x and y.
msg47834 - (view) Author: Martin v. Löwis (loewis) * (Python committer) Date: 2005-02-21 22:37
Logged In: YES 
user_id=21627

As for the semantic change: I believe (without testing) that
the patch will change the output of the attached script
(a.py). Now, I agree that this is almost the point of the
patch, but it is still a change in observable behaviour.   
I say almost, because the point of the patch is to omit
*unnecessary* dict lookups. Whether or not the lookup is
unnecessary is difficult to tell if the dictionary is a dict
subtype.

It might be relevant to some users - for example, I meant to
implement expression evaluation in the context of a CORBA
NamingService::NamingContext a few years ago (the
application could not be implemented because exec would not
accept non-dict objects at the time). In this context, the
namespace for the exec would be a live object, and there
would be no guarantee that a read gives you back what a
write just set (e.g. due to interleaving with other
activities, or due to a custom implementation of NamingContext).

All that said, I do believe that the change in semantics is
minor, and should not stop the patch. All I want is that it
is understood that there *is* a change in semantics.

I'm personally more worried about the change in the byte
code format, because it means that the next release won't be
able to share byte code files with the current release
*again*. This is for python-dev discussion, though.
msg47835 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2005-02-21 23:00
Logged In: YES 
user_id=80475

Marking this as deferred. By itself, there is not enough
gain to warrant losing pyc sharing with Py2.4.  If something
else changes the bytecode, will put this in as the issue
will be moot. 

Out of curiousity, would the COBRA naming service have
needed the getitem immediately following a setitem to the
same key?  Would it have returned something different than
the value just set?
msg47836 - (view) Author: Martin v. Löwis (loewis) * (Python committer) Date: 2005-02-21 23:07
Logged In: YES 
user_id=21627

In the specific naming service implementation, it would have
been extremely unlikely that you get a different value on
reading; out of its own, it would have always returned the
same objects. There was a small (but real) chance that a
different application interfered (CORBA being a distributed
system), in which case you would have read that the value
stored by the other application. This would have likely
occurred only in overload situations (i.e. when the naming
service starts queueing requests from clients)
History
Date User Action Args
2022-04-11 14:56:09adminsetgithub: 41608
2005-02-20 15:41:48rhettingercreate