Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Handle check for sending None to starting generator and coroutine int…
…o bytecode.
  • Loading branch information
markshannon committed Mar 31, 2021
commit 935b54a39f8b1f9f03fd5444af904853df84472a
1 change: 1 addition & 0 deletions Include/opcode.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Lib/opcode.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ def jabs_op(name, op):
name_op('DELETE_ATTR', 96) # ""
name_op('STORE_GLOBAL', 97) # ""
name_op('DELETE_GLOBAL', 98) # ""

def_op('GEN_START', 99)
def_op('LOAD_CONST', 100) # Index in const list
hasconst.append(100)
name_op('LOAD_NAME', 101) # Index in name list
Expand Down
27 changes: 6 additions & 21 deletions Objects/genobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -176,27 +176,12 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult,
}

assert(_PyFrame_IsRunnable(f));
if (f->f_lasti == -1) {
if (arg && arg != Py_None) {
const char *msg = "can't send non-None value to a "
"just-started generator";
if (PyCoro_CheckExact(gen)) {
msg = NON_INIT_CORO_MSG;
}
else if (PyAsyncGen_CheckExact(gen)) {
msg = "can't send non-None value to a "
"just-started async generator";
}
PyErr_SetString(PyExc_TypeError, msg);
return PYGEN_ERROR;
}
} else {
/* Push arg onto the frame's value stack */
result = arg ? arg : Py_None;
Py_INCREF(result);
gen->gi_frame->f_valuestack[gen->gi_frame->f_stackdepth] = result;
gen->gi_frame->f_stackdepth++;
}
assert(f->f_lasti >= 0 || PyBytes_AS_STRING(f->f_code->co_code)[0] == GEN_START);
/* Push arg onto the frame's value stack */
result = arg ? arg : Py_None;
Py_INCREF(result);
gen->gi_frame->f_valuestack[gen->gi_frame->f_stackdepth] = result;
gen->gi_frame->f_stackdepth++;

/* Generators always return to their most recent caller, not
* necessarily their creator. */
Expand Down
20 changes: 20 additions & 0 deletions Python/ceval.c
Original file line number Diff line number Diff line change
Expand Up @@ -2651,6 +2651,26 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
goto exiting;
}

case TARGET(GEN_START): {
assert(oparg < 3);
PyObject *none = POP();
Py_DECREF(none);
if (none != Py_None) {
static const char *gen_kind[3] = {
"generator",
"coroutine",
"async generator"
};
_PyErr_Format(tstate, PyExc_TypeError,
"can't send non-None value to a "
"just-started %s",
gen_kind[oparg]);
goto error;
}
DISPATCH();
}


case TARGET(POP_EXCEPT): {
PyObject *type, *value, *traceback;
_PyErr_StackItem *exc_info;
Expand Down
48 changes: 47 additions & 1 deletion Python/compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -1140,6 +1140,8 @@ stack_effect(int opcode, int oparg, int jump)
return 1;
case LIST_TO_TUPLE:
return 0;
case GEN_START:
return -1;
case LIST_EXTEND:
case SET_UPDATE:
case DICT_MERGE:
Expand Down Expand Up @@ -6169,7 +6171,11 @@ stackdepth(struct compiler *c)
}

sp = stack;
stackdepth_push(&sp, entryblock, 0);
if (c->u->u_ste->ste_generator || c->u->u_ste->ste_coroutine) {
stackdepth_push(&sp, entryblock, 1);
} else {
stackdepth_push(&sp, entryblock, 0);
}
while (sp != stack) {
b = *--sp;
int depth = b->b_startdepth;
Expand Down Expand Up @@ -6649,6 +6655,41 @@ optimize_cfg(struct assembler *a, PyObject *consts);
static int
ensure_exits_have_lineno(struct compiler *c);

static int
insert_generator_prefix(struct compiler *c, basicblock *entryblock) {

int flags = compute_code_flags(c);
if (flags < 0) {
return -1;
}
int kind;
if (flags & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR)) {
if (flags & CO_COROUTINE) {
kind = 1;
}
else if (flags & CO_ASYNC_GENERATOR) {
kind = 2;
}
else {
kind = 0;
}
}
else {
return 0;
}
if (compiler_next_instr(entryblock) < 0) {
return -1;
}
for (int i = entryblock->b_iused-1; i > 0; i--) {
entryblock->b_instr[i] = entryblock->b_instr[i-1];
}
entryblock->b_instr[0].i_opcode = GEN_START;
entryblock->b_instr[0].i_oparg = kind;
entryblock->b_instr[0].i_lineno = -1;
entryblock->b_instr[0].i_target = NULL;
return 0;
}

static PyCodeObject *
assemble(struct compiler *c, int addNone)
{
Expand All @@ -6669,6 +6710,7 @@ assemble(struct compiler *c, int addNone)
ADDOP(c, RETURN_VALUE);
}


for (basicblock *b = c->u->u_blocks; b != NULL; b = b->b_list) {
if (normalize_basic_block(b)) {
return NULL;
Expand All @@ -6686,6 +6728,10 @@ assemble(struct compiler *c, int addNone)
entryblock = b;
}

if (insert_generator_prefix(c, entryblock)) {
goto error;
}

/* Set firstlineno if it wasn't explicitly set. */
if (!c->u->u_firstlineno) {
if (entryblock && entryblock->b_instr && entryblock->b_instr->i_lineno)
Expand Down
Loading