Great analysis! What might stand in the way of adoption is concern for
bytecode manipulation libraries that would have to be changed. What
might encourage adoption would be a benchmark showing this saves a lot
of time.

Personally I'm expecting it won't make much of a difference for real
programs since almost always the cost of creating the function is
dwarfed by the (total) cost of running it. But Python does create a
lot of functions, and there's also lambdas.

There's also talk of switching to wordcode, in a different thread.
Maybe the idea would be easier to introduce there? (Bytecode libraries
would have to change anyways, so the additional concern for this
change would be minimal.)

On Thu, Apr 14, 2016 at 2:04 AM, Nikita Nemkin <nik...@nemkin.ru> wrote:
> MAKE_FUNCTION opcode is complex due to the way it receives
> input arguments:
>
>  1) default args, individually;
>  2) default kwonly args, individual name-value pairs;
>  3) a tuple of parameter names (single constant);
>  4) annotation values, individually;
>  5) code object;
>  6) qualname.
>
> The counts for 1,2,4 are packed into oparg bitfields, making oparg large.
>
> My suggestion is to pre-package 1-4 before calling MAKE_FUNCTION,
> i.e. explicitly emit BUILD_TUPLE for defaults args and BUILD_MAPs
> for keyword defaults and annotations.
>
> Then, MAKE_FUNCTION will become a dramatically simpler
> 5 argument opcode, taking
>
>  1) default args tuple (optional);
>  2) default keyword only args dict (optional);
>  3) annotations dict (optional);
>  4) code object;
>  5) qualname.
>
> These arguments correspond exactly to __annotations__, __kwdefaults__,
> __defaults__, __code__ and __qualname__ attributes.
>
> For optional args, oparg bits should indicate individual arg presence.
> (This also saves None checks in opcode implementation.)
>
> If we add another optional argument (and oparg bit) for __closure__
> attribute, then separate MAKE_CLOSURE opcode becomes unnecessary.
>
> Default args tuple is likely to be a constant and can be packaged whole,
> compensating for the extra size of explicit BUILD_* instructions.
>
> Compare the current implementation:
>
>     https://github.com/python/cpython/blob/master/Python/ceval.c#L3262
>
> with this provisional implementation (untested):
>
>     TARGET(MAKE_FUNCTION) {
>         PyObject *qualname = POP();
>         PyObject *codeobj = POP();
>         PyFunctionObject *func;
>         func = (PyFunctionObject *)PyFunction_NewWithQualName(
>                                        codeobj, f->f_globals, qualname);
>         Py_DECREF(codeobj);
>         Py_DECREF(qualname);
>         if (func == NULL)
>             goto error;
>
>         /* NB: Py_None is not an acceptable value for these. */
>         if (oparg & 0x08)
>             func->func_closure = POP();
>         if (oparg & 0x04)
>             func->func_annotations = POP();
>         if (oparg & 0x02)
>             func->func_kwdefaults = POP();
>         if (oparg & 0x01)
>             func->func_defaults = POP();
>
>         PUSH((PyObject *)func);
>         DISPATCH();
>     }
>
> compile.c also gets a bit simpler, but not much.
>
> What do you think?
> _______________________________________________
> Python-Dev mailing list
> Python-Dev@python.org
> https://mail.python.org/mailman/listinfo/python-dev
> Unsubscribe: 
> https://mail.python.org/mailman/options/python-dev/guido%40python.org



-- 
--Guido van Rossum (python.org/~guido)
_______________________________________________
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com

Reply via email to