[issue42033] Seemingly unnecessary complexification of foo(**kw)

2020-12-16 Thread Josh Rosenberg


Josh Rosenberg  added the comment:

Even if making a copy is necessary when the underlying function receives the 
dict "raw", preemptively performing the copy (before knowing if the function 
being called is a Vectorcall function) means that when it's a Vectorcall 
function (e.g. all user-defined functions, right?), instead of just copying 
from the original dict to the unpacked stack for vectorcall, it makes an 
intermediate copy, then copies from that copy to the unpacked stack later on; 
the copy is otherwise completely unused.

The extra bytecode isn't even defending against "dict-like" kwargs, because 
CALL_FUNCTION_EX itself already copies to a true dict for anything that's not 
an exact dict (that defense shouldn't even be there if the bytecode compiler is 
already guaranteeing a true dict).

Seems like, if preventing the caller's dict from being passed directly to the 
underlying function is necessary and intended, it should be done in 
PyObject_Call (which can avoid the copy entirely when call a Vectorcall 
function and when the reference count on the dict is 1), not at the bytecode 
interpreter layer. As is, PyObject_Call is already violating the documented 
behavior by *not* matching the behavior of callable(*args, **kwargs) (see 
#42629), so moving it to PyObject_Call would fix that problem and improve 
performance passing a single kwargs.

--

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue42033] Seemingly unnecessary complexification of foo(**kw)

2020-10-15 Thread Josh Rosenberg


Change by Josh Rosenberg :


--
nosy: +josh.r

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue42033] Seemingly unnecessary complexification of foo(**kw)

2020-10-15 Thread Serhiy Storchaka


Serhiy Storchaka  added the comment:

$ python3.8 -m timeit -s "a = {'a': 1}" "dict(**a)"
200 loops, best of 5: 113 nsec per loop
$ python3.9 -m timeit -s "a = {'a': 1}" "dict(**a)"
200 loops, best of 5: 181 nsec per loop

--
nosy: +serhiy.storchaka

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue42033] Seemingly unnecessary complexification of foo(**kw)

2020-10-15 Thread Brandt Bucher


Change by Brandt Bucher :


--
nosy: +brandtbucher

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue42033] Seemingly unnecessary complexification of foo(**kw)

2020-10-15 Thread Xavier Morel

Xavier Morel  added the comment:

I have not noticed anything, I was just looking at the bytecode changes and 
stumbled upon this oddity. Though I would expect a small slowdown as every 
fn(**kw) would now incur an extra dict copy, unless there’s something in 
call_function_ex which copies the input dict iff its ref count is not one?

For whatever that’s worth, the 3.8 bytecode has been there since 
call_function_ex was added in 3.6 and before that call_function_kw looks 
identical (load_global foo, load_local var, call_function_kw)

--

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue42033] Seemingly unnecessary complexification of foo(**kw)

2020-10-15 Thread Mark Shannon


Mark Shannon  added the comment:

Have you observed any slowdown or incorrect behaviour?

The 3.8 bytecode looks incorrect to me.
The C-API documentation doesn't prohibit callables from mutating the dictionary 
they receive.
Unless a copy is made, then a callee could mutate `var`.

https://docs.python.org/3/c-api/call.html

--

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue42033] Seemingly unnecessary complexification of foo(**kw)

2020-10-15 Thread Raymond Hettinger


Change by Raymond Hettinger :


--
assignee:  -> Mark.Shannon

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue42033] Seemingly unnecessary complexification of foo(**kw)

2020-10-14 Thread Xavier Morel


New submission from Xavier Morel :

Following bpo-39320 the highly specialised bytecode for vararg calls were 
replaced by simpler ones, but there seems to be at least one area where the 
generated bytecode regressed for possibly no reason?

In Python 3.8, foo(**var) compiles to:

0 LOAD_GLOBAL  0 (foo)
2 BUILD_TUPLE  0
4 LOAD_FAST2 (var)
6 CALL_FUNCTION_EX 1

In Python 3.9, it compiles to:

0 LOAD_GLOBAL  0 (foo)
2 BUILD_TUPLE  0
4 BUILD_MAP0
6 LOAD_FAST2 (var)
8 DICT_MERGE   1
0 CALL_FUNCTION_EX 1

The PR 18141 does not seem to change the implementation of CALL_FUNCTION_EX so 
I would expect that if it was fine with taking the `var` arbitrary mapping 
before it stil is now, and the extra two opcodes (and creation of a dict) is 
unnecessary?

--
messages: 378613
nosy: Mark.Shannon, xmorel
priority: normal
severity: normal
status: open
title: Seemingly unnecessary complexification of foo(**kw)
versions: Python 3.9

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com