-
Notifications
You must be signed in to change notification settings - Fork 51
Insert shim frames at entries points to the interpreter. #436
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Interesting. The question is whether we save enough on simplified returns (really just one check that the CPU can probably figure out is almost always taken) to dispatch for an extra opcode. Is this measurable? Are there other benefits? |
Yes. This should allow us to inline generator iteration and |
If |
The current behavior of If you want to propose to the wider community fixing all the weird corner cases, I'd be delighted. |
Done |
We should insert shim frames where the C-API calls into the interpreter.
The idea is that we can simplify returns and yields, as they can assume that it is safe to just pop the current frame and continue interpretation.
The places where we enter the interpreter from the C-API are:
PyEval_EvalFrame
PyEval_EvalFrameEx
_PyEval_Vector
The interpreter is also called from
gen_send_ex2
, but that's not directly part of the C-API, although its callers are.Starting with the simplest case, the C-API functions listed above (except
gen_send_ex2
), we need to push a frame with a single stack entry andEXIT_INTERPRETER
as its sole instruction.This allows us to simplify
RETURN_VALUE
andRETURN_GENERATOR
as they no longer need to check whether the frame is an entry frame.RETURN_VALUE
goes fromto
Similarly for
RETURN_GENERATOR
.The new
EXIT_INTERPRETER
instruction is defined as:So far, so good. But things get a bit more complex with
YIELD_VALUE
. First off we add ayield_offset
to the interpreter frame, so thatyield
ing goes to a different location thanRETURN_VALUE
. This should allow us to inline generator iteration andyield from
in a similar way to calls.To get this to work we will need to implement the following in bytecode:
gen.__next__()
,gen.send()
,gen.throw()
,gen.close()
,coro.send()
,async_gen.throw()
, etc.gen.__next__()
could be implemented as follows:The other functions are left as an exercise for the reader 🙂
We could start by implementing
gen_send_ex2
as bytecode, then re-implementing its callers in bytecode until we can dicardgen_send_ex2
.It might also be useful to implement
next()
in bytecode to avoid the context swap.next()
:The text was updated successfully, but these errors were encountered: