summaryrefslogtreecommitdiffstats
path: root/Python/compile.c
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2018-02-22 21:33:30 (GMT)
committerGitHub <noreply@github.com>2018-02-22 21:33:30 (GMT)
commit520b7ae27e39d1c77ea74ccd1b184d7cb43f9dcb (patch)
tree8a661515a3574b0d79ea2024a3b92646dd7ee837 /Python/compile.c
parent4af8fd561433826ac897c55e41a087a5c5dbacf3 (diff)
downloadcpython-520b7ae27e39d1c77ea74ccd1b184d7cb43f9dcb.zip
cpython-520b7ae27e39d1c77ea74ccd1b184d7cb43f9dcb.tar.gz
cpython-520b7ae27e39d1c77ea74ccd1b184d7cb43f9dcb.tar.bz2
bpo-17611. Move unwinding of stack for "pseudo exceptions" from interpreter to compiler. (GH-5006)
Co-authored-by: Mark Shannon <mark@hotpy.org> Co-authored-by: Antoine Pitrou <antoine@python.org>
Diffstat (limited to 'Python/compile.c')
-rw-r--r--Python/compile.c409
1 files changed, 244 insertions, 165 deletions
diff --git a/Python/compile.c b/Python/compile.c
index 0dc3566..f14647b 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -81,11 +81,14 @@ It's called a frame block to distinguish it from a basic block in the
compiler IR.
*/
-enum fblocktype { LOOP, EXCEPT, FINALLY_TRY, FINALLY_END };
+enum fblocktype { WHILE_LOOP, FOR_LOOP, EXCEPT, FINALLY_TRY, FINALLY_END,
+ WITH, ASYNC_WITH, HANDLER_CLEANUP };
struct fblockinfo {
enum fblocktype fb_type;
basicblock *fb_block;
+ /* (optional) type-specific exit or cleanup block */
+ basicblock *fb_exit;
};
enum {
@@ -183,13 +186,6 @@ static int compiler_annassign(struct compiler *, stmt_ty);
static int compiler_visit_slice(struct compiler *, slice_ty,
expr_context_ty);
-static int compiler_push_fblock(struct compiler *, enum fblocktype,
- basicblock *);
-static void compiler_pop_fblock(struct compiler *, enum fblocktype,
- basicblock *);
-/* Returns true if there is a loop on the fblock stack. */
-static int compiler_in_loop(struct compiler *);
-
static int inplace_binop(struct compiler *, operator_ty);
static int expr_constant(expr_ty);
@@ -846,7 +842,7 @@ compiler_next_instr(struct compiler *c, basicblock *b)
- when entering a new scope
- on each statement
- on each expression that start a new line
- - before the "except" clause
+ - before the "except" and "finally" clauses
- before the "for" and "while" expressions
*/
@@ -881,6 +877,7 @@ stack_effect(int opcode, int oparg, int jump)
return -1;
case ROT_TWO:
case ROT_THREE:
+ case ROT_FOUR:
return 0;
case DUP_TOP:
return 1;
@@ -947,8 +944,7 @@ stack_effect(int opcode, int oparg, int jump)
case INPLACE_XOR:
case INPLACE_OR:
return -1;
- case BREAK_LOOP:
- return 0;
+
case SETUP_WITH:
/* 1 in the normal flow.
* Restore the stack position and push 6 values before jumping to
@@ -975,6 +971,7 @@ stack_effect(int opcode, int oparg, int jump)
case POP_EXCEPT:
return -3;
case END_FINALLY:
+ case POP_FINALLY:
/* Pop 6 values when an exception was raised. */
return -6;
@@ -1043,16 +1040,20 @@ stack_effect(int opcode, int oparg, int jump)
case LOAD_GLOBAL:
return 1;
- case CONTINUE_LOOP:
- return 0;
- case SETUP_LOOP:
- return 0;
- case SETUP_EXCEPT:
+ /* Exception handling */
case SETUP_FINALLY:
/* 0 in the normal flow.
* Restore the stack position and push 6 values before jumping to
* the handler if an exception be raised. */
return jump ? 6 : 0;
+ case BEGIN_FINALLY:
+ /* Actually pushes 1 value, but count 6 for balancing with
+ * END_FINALLY and POP_FINALLY.
+ * This is the main reason of using this opcode instead of
+ * "LOAD_CONST None". */
+ return 6;
+ case CALL_FINALLY:
+ return jump ? 1 : 0;
case LOAD_FAST:
return 1;
@@ -1458,6 +1459,103 @@ find_ann(asdl_seq *stmts)
return res;
}
+/*
+ * Frame block handling functions
+ */
+
+static int
+compiler_push_fblock(struct compiler *c, enum fblocktype t, basicblock *b,
+ basicblock *exit)
+{
+ struct fblockinfo *f;
+ if (c->u->u_nfblocks >= CO_MAXBLOCKS) {
+ PyErr_SetString(PyExc_SyntaxError,
+ "too many statically nested blocks");
+ return 0;
+ }
+ f = &c->u->u_fblock[c->u->u_nfblocks++];
+ f->fb_type = t;
+ f->fb_block = b;
+ f->fb_exit = exit;
+ return 1;
+}
+
+static void
+compiler_pop_fblock(struct compiler *c, enum fblocktype t, basicblock *b)
+{
+ struct compiler_unit *u = c->u;
+ assert(u->u_nfblocks > 0);
+ u->u_nfblocks--;
+ assert(u->u_fblock[u->u_nfblocks].fb_type == t);
+ assert(u->u_fblock[u->u_nfblocks].fb_block == b);
+}
+
+/* Unwind a frame block. If preserve_tos is true, the TOS before
+ * popping the blocks will be restored afterwards.
+ */
+static int
+compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info,
+ int preserve_tos)
+{
+ switch (info->fb_type) {
+ case WHILE_LOOP:
+ return 1;
+
+ case FINALLY_END:
+ ADDOP_I(c, POP_FINALLY, preserve_tos);
+ return 1;
+
+ case FOR_LOOP:
+ /* Pop the iterator */
+ if (preserve_tos) {
+ ADDOP(c, ROT_TWO);
+ }
+ ADDOP(c, POP_TOP);
+ return 1;
+
+ case EXCEPT:
+ ADDOP(c, POP_BLOCK);
+ return 1;
+
+ case FINALLY_TRY:
+ ADDOP(c, POP_BLOCK);
+ ADDOP_JREL(c, CALL_FINALLY, info->fb_exit);
+ return 1;
+
+ case WITH:
+ case ASYNC_WITH:
+ ADDOP(c, POP_BLOCK);
+ if (preserve_tos) {
+ ADDOP(c, ROT_TWO);
+ }
+ ADDOP(c, BEGIN_FINALLY);
+ ADDOP(c, WITH_CLEANUP_START);
+ if (info->fb_type == ASYNC_WITH) {
+ ADDOP(c, GET_AWAITABLE);
+ ADDOP_O(c, LOAD_CONST, Py_None, consts);
+ ADDOP(c, YIELD_FROM);
+ }
+ ADDOP(c, WITH_CLEANUP_FINISH);
+ ADDOP_I(c, POP_FINALLY, 0);
+ return 1;
+
+ case HANDLER_CLEANUP:
+ if (preserve_tos) {
+ ADDOP(c, ROT_FOUR);
+ }
+ if (info->fb_exit) {
+ ADDOP(c, POP_BLOCK);
+ ADDOP(c, POP_EXCEPT);
+ ADDOP_JREL(c, CALL_FINALLY, info->fb_exit);
+ }
+ else {
+ ADDOP(c, POP_EXCEPT);
+ }
+ return 1;
+ }
+ Py_UNREACHABLE();
+}
+
/* Compile a sequence of statements, checking for a docstring
and for annotations. */
@@ -2312,9 +2410,10 @@ compiler_for(struct compiler *c, stmt_ty s)
end = compiler_new_block(c);
if (start == NULL || end == NULL || cleanup == NULL)
return 0;
- ADDOP_JREL(c, SETUP_LOOP, end);
- if (!compiler_push_fblock(c, LOOP, start))
+
+ if (!compiler_push_fblock(c, FOR_LOOP, start, end))
return 0;
+
VISIT(c, expr, s->v.For.iter);
ADDOP(c, GET_ITER);
compiler_use_next_block(c, start);
@@ -2323,8 +2422,9 @@ compiler_for(struct compiler *c, stmt_ty s)
VISIT_SEQ(c, stmt, s->v.For.body);
ADDOP_JABS(c, JUMP_ABSOLUTE, start);
compiler_use_next_block(c, cleanup);
- ADDOP(c, POP_BLOCK);
- compiler_pop_fblock(c, LOOP, start);
+
+ compiler_pop_fblock(c, FOR_LOOP, start);
+
VISIT_SEQ(c, stmt, s->v.For.orelse);
compiler_use_next_block(c, end);
return 1;
@@ -2356,8 +2456,7 @@ compiler_async_for(struct compiler *c, stmt_ty s)
|| after_try == NULL || try_cleanup == NULL)
return 0;
- ADDOP_JREL(c, SETUP_LOOP, after_loop);
- if (!compiler_push_fblock(c, LOOP, try))
+ if (!compiler_push_fblock(c, FOR_LOOP, try, after_loop))
return 0;
VISIT(c, expr, s->v.AsyncFor.iter);
@@ -2366,19 +2465,21 @@ compiler_async_for(struct compiler *c, stmt_ty s)
compiler_use_next_block(c, try);
- ADDOP_JREL(c, SETUP_EXCEPT, except);
- if (!compiler_push_fblock(c, EXCEPT, try))
+ /* SETUP_FINALLY to guard the __anext__ call */
+ ADDOP_JREL(c, SETUP_FINALLY, except);
+ if (!compiler_push_fblock(c, EXCEPT, try, NULL))
return 0;
ADDOP(c, GET_ANEXT);
ADDOP_O(c, LOAD_CONST, Py_None, consts);
ADDOP(c, YIELD_FROM);
VISIT(c, expr, s->v.AsyncFor.target);
- ADDOP(c, POP_BLOCK);
+ ADDOP(c, POP_BLOCK); /* for SETUP_FINALLY */
compiler_pop_fblock(c, EXCEPT, try);
ADDOP_JREL(c, JUMP_FORWARD, after_try);
+ /* Except block for __anext__ */
compiler_use_next_block(c, except);
ADDOP(c, DUP_TOP);
ADDOP_O(c, LOAD_GLOBAL, stop_aiter_error, names);
@@ -2388,25 +2489,26 @@ compiler_async_for(struct compiler *c, stmt_ty s)
ADDOP(c, POP_TOP);
ADDOP(c, POP_TOP);
ADDOP(c, POP_TOP);
- ADDOP(c, POP_EXCEPT); /* for SETUP_EXCEPT */
- ADDOP(c, POP_TOP); /* for correct calculation of stack effect */
- ADDOP(c, POP_BLOCK); /* for SETUP_LOOP */
+ ADDOP(c, POP_EXCEPT); /* for SETUP_FINALLY */
+ ADDOP(c, POP_TOP); /* pop iterator from stack */
ADDOP_JABS(c, JUMP_ABSOLUTE, after_loop_else);
compiler_use_next_block(c, try_cleanup);
ADDOP(c, END_FINALLY);
+ /* Success block for __anext__ */
compiler_use_next_block(c, after_try);
VISIT_SEQ(c, stmt, s->v.AsyncFor.body);
ADDOP_JABS(c, JUMP_ABSOLUTE, try);
- ADDOP(c, POP_BLOCK); /* for SETUP_LOOP */
- compiler_pop_fblock(c, LOOP, try);
+ compiler_pop_fblock(c, FOR_LOOP, try);
+ /* Block reached after `break`ing from loop */
compiler_use_next_block(c, after_loop);
ADDOP_JABS(c, JUMP_ABSOLUTE, end);
+ /* `else` block */
compiler_use_next_block(c, after_loop_else);
VISIT_SEQ(c, stmt, s->v.For.orelse);
@@ -2443,9 +2545,8 @@ compiler_while(struct compiler *c, stmt_ty s)
else
orelse = NULL;
- ADDOP_JREL(c, SETUP_LOOP, end);
compiler_use_next_block(c, loop);
- if (!compiler_push_fblock(c, LOOP, loop))
+ if (!compiler_push_fblock(c, WHILE_LOOP, loop, end))
return 0;
if (constant == -1) {
if (!compiler_jump_if(c, s->v.While.test, anchor, 0))
@@ -2460,8 +2561,8 @@ compiler_while(struct compiler *c, stmt_ty s)
if (constant == -1)
compiler_use_next_block(c, anchor);
- ADDOP(c, POP_BLOCK);
- compiler_pop_fblock(c, LOOP, loop);
+ compiler_pop_fblock(c, WHILE_LOOP, loop);
+
if (orelse != NULL) /* what if orelse is just pass? */
VISIT_SEQ(c, stmt, s->v.While.orelse);
compiler_use_next_block(c, end);
@@ -2470,46 +2571,83 @@ compiler_while(struct compiler *c, stmt_ty s)
}
static int
-compiler_continue(struct compiler *c)
+compiler_return(struct compiler *c, stmt_ty s)
{
- static const char LOOP_ERROR_MSG[] = "'continue' not properly in loop";
- static const char IN_FINALLY_ERROR_MSG[] =
- "'continue' not supported inside 'finally' clause";
- int i;
+ int preserve_tos = ((s->v.Return.value != NULL) &&
+ !is_const(s->v.Return.value));
+ if (c->u->u_ste->ste_type != FunctionBlock)
+ return compiler_error(c, "'return' outside function");
+ if (s->v.Return.value != NULL &&
+ c->u->u_ste->ste_coroutine && c->u->u_ste->ste_generator)
+ {
+ return compiler_error(
+ c, "'return' with value in async generator");
+ }
+ if (preserve_tos) {
+ VISIT(c, expr, s->v.Return.value);
+ }
+ for (int depth = c->u->u_nfblocks; depth--;) {
+ struct fblockinfo *info = &c->u->u_fblock[depth];
- if (!c->u->u_nfblocks)
- return compiler_error(c, LOOP_ERROR_MSG);
- i = c->u->u_nfblocks - 1;
- switch (c->u->u_fblock[i].fb_type) {
- case LOOP:
- ADDOP_JABS(c, JUMP_ABSOLUTE, c->u->u_fblock[i].fb_block);
- break;
- case EXCEPT:
- case FINALLY_TRY:
- while (--i >= 0 && c->u->u_fblock[i].fb_type != LOOP) {
- /* Prevent continue anywhere under a finally
- even if hidden in a sub-try or except. */
- if (c->u->u_fblock[i].fb_type == FINALLY_END)
- return compiler_error(c, IN_FINALLY_ERROR_MSG);
- }
- if (i == -1)
- return compiler_error(c, LOOP_ERROR_MSG);
- ADDOP_JABS(c, CONTINUE_LOOP, c->u->u_fblock[i].fb_block);
- break;
- case FINALLY_END:
- return compiler_error(c, IN_FINALLY_ERROR_MSG);
+ if (!compiler_unwind_fblock(c, info, preserve_tos))
+ return 0;
+ }
+ if (s->v.Return.value == NULL) {
+ ADDOP_O(c, LOAD_CONST, Py_None, consts);
+ }
+ else if (!preserve_tos) {
+ VISIT(c, expr, s->v.Return.value);
}
+ ADDOP(c, RETURN_VALUE);
return 1;
}
+static int
+compiler_break(struct compiler *c)
+{
+ for (int depth = c->u->u_nfblocks; depth--;) {
+ struct fblockinfo *info = &c->u->u_fblock[depth];
+
+ if (!compiler_unwind_fblock(c, info, 0))
+ return 0;
+ if (info->fb_type == WHILE_LOOP || info->fb_type == FOR_LOOP) {
+ ADDOP_JABS(c, JUMP_ABSOLUTE, info->fb_exit);
+ return 1;
+ }
+ }
+ return compiler_error(c, "'break' outside loop");
+}
+
+static int
+compiler_continue(struct compiler *c)
+{
+ for (int depth = c->u->u_nfblocks; depth--;) {
+ struct fblockinfo *info = &c->u->u_fblock[depth];
+
+ if (info->fb_type == WHILE_LOOP || info->fb_type == FOR_LOOP) {
+ ADDOP_JABS(c, JUMP_ABSOLUTE, info->fb_block);
+ return 1;
+ }
+ if (info->fb_type == FINALLY_END) {
+ return compiler_error(c,
+ "'continue' not supported inside 'finally' clause");
+ }
+ if (!compiler_unwind_fblock(c, info, 0))
+ return 0;
+ }
+ return compiler_error(c, "'continue' not properly in loop");
+}
+
+
/* Code generated for "try: <body> finally: <finalbody>" is as follows:
SETUP_FINALLY L
<code for body>
POP_BLOCK
- LOAD_CONST <None>
- L: <code for finalbody>
+ BEGIN_FINALLY
+ L:
+ <code for finalbody>
END_FINALLY
The special instructions use the block stack. Each block
@@ -2521,33 +2659,34 @@ compiler_continue(struct compiler *c)
Pushes the current value stack level and the label
onto the block stack.
POP_BLOCK:
- Pops en entry from the block stack, and pops the value
- stack until its level is the same as indicated on the
- block stack. (The label is ignored.)
+ Pops en entry from the block stack.
+ BEGIN_FINALLY
+ Pushes NULL onto the value stack.
END_FINALLY:
- Pops a variable number of entries from the *value* stack
- and re-raises the exception they specify. The number of
- entries popped depends on the (pseudo) exception type.
+ Pops 1 (NULL or int) or 6 entries from the *value* stack and restore
+ the raised and the caught exceptions they specify.
The block stack is unwound when an exception is raised:
- when a SETUP_FINALLY entry is found, the exception is pushed
- onto the value stack (and the exception condition is cleared),
- and the interpreter jumps to the label gotten from the block
- stack.
+ when a SETUP_FINALLY entry is found, the raised and the caught
+ exceptions are pushed onto the value stack (and the exception
+ condition is cleared), and the interpreter jumps to the label
+ gotten from the block stack.
*/
static int
compiler_try_finally(struct compiler *c, stmt_ty s)
{
basicblock *body, *end;
+
body = compiler_new_block(c);
end = compiler_new_block(c);
if (body == NULL || end == NULL)
return 0;
+ /* `try` block */
ADDOP_JREL(c, SETUP_FINALLY, end);
compiler_use_next_block(c, body);
- if (!compiler_push_fblock(c, FINALLY_TRY, body))
+ if (!compiler_push_fblock(c, FINALLY_TRY, body, end))
return 0;
if (s->v.Try.handlers && asdl_seq_LEN(s->v.Try.handlers)) {
if (!compiler_try_except(c, s))
@@ -2557,16 +2696,16 @@ compiler_try_finally(struct compiler *c, stmt_ty s)
VISIT_SEQ(c, stmt, s->v.Try.body);
}
ADDOP(c, POP_BLOCK);
+ ADDOP(c, BEGIN_FINALLY);
compiler_pop_fblock(c, FINALLY_TRY, body);
- ADDOP_O(c, LOAD_CONST, Py_None, consts);
+ /* `finally` block */
compiler_use_next_block(c, end);
- if (!compiler_push_fblock(c, FINALLY_END, end))
+ if (!compiler_push_fblock(c, FINALLY_END, end, NULL))
return 0;
VISIT_SEQ(c, stmt, s->v.Try.finalbody);
ADDOP(c, END_FINALLY);
compiler_pop_fblock(c, FINALLY_END, end);
-
return 1;
}
@@ -2577,7 +2716,7 @@ compiler_try_finally(struct compiler *c, stmt_ty s)
associated value, and 'exc' the exception.)
Value stack Label Instruction Argument
- [] SETUP_EXCEPT L1
+ [] SETUP_FINALLY L1
[] <code for S>
[] POP_BLOCK
[] JUMP_FORWARD L0
@@ -2613,9 +2752,9 @@ compiler_try_except(struct compiler *c, stmt_ty s)
end = compiler_new_block(c);
if (body == NULL || except == NULL || orelse == NULL || end == NULL)
return 0;
- ADDOP_JREL(c, SETUP_EXCEPT, except);
+ ADDOP_JREL(c, SETUP_FINALLY, except);
compiler_use_next_block(c, body);
- if (!compiler_push_fblock(c, EXCEPT, body))
+ if (!compiler_push_fblock(c, EXCEPT, body, NULL))
return 0;
VISIT_SEQ(c, stmt, s->v.Try.body);
ADDOP(c, POP_BLOCK);
@@ -2666,25 +2805,23 @@ compiler_try_except(struct compiler *c, stmt_ty s)
/* second try: */
ADDOP_JREL(c, SETUP_FINALLY, cleanup_end);
compiler_use_next_block(c, cleanup_body);
- if (!compiler_push_fblock(c, FINALLY_TRY, cleanup_body))
+ if (!compiler_push_fblock(c, HANDLER_CLEANUP, cleanup_body, cleanup_end))
return 0;
/* second # body */
VISIT_SEQ(c, stmt, handler->v.ExceptHandler.body);
ADDOP(c, POP_BLOCK);
- compiler_pop_fblock(c, FINALLY_TRY, cleanup_body);
+ ADDOP(c, BEGIN_FINALLY);
+ compiler_pop_fblock(c, HANDLER_CLEANUP, cleanup_body);
/* finally: */
- ADDOP_O(c, LOAD_CONST, Py_None, consts);
compiler_use_next_block(c, cleanup_end);
- if (!compiler_push_fblock(c, FINALLY_END, cleanup_end))
+ if (!compiler_push_fblock(c, FINALLY_END, cleanup_end, NULL))
return 0;
- /* name = None */
+ /* name = None; del name */
ADDOP_O(c, LOAD_CONST, Py_None, consts);
compiler_nameop(c, handler->v.ExceptHandler.name, Store);
-
- /* del name */
compiler_nameop(c, handler->v.ExceptHandler.name, Del);
ADDOP(c, END_FINALLY);
@@ -2701,11 +2838,11 @@ compiler_try_except(struct compiler *c, stmt_ty s)
ADDOP(c, POP_TOP);
ADDOP(c, POP_TOP);
compiler_use_next_block(c, cleanup_body);
- if (!compiler_push_fblock(c, FINALLY_TRY, cleanup_body))
+ if (!compiler_push_fblock(c, HANDLER_CLEANUP, cleanup_body, NULL))
return 0;
VISIT_SEQ(c, stmt, handler->v.ExceptHandler.body);
ADDOP(c, POP_EXCEPT);
- compiler_pop_fblock(c, FINALLY_TRY, cleanup_body);
+ compiler_pop_fblock(c, HANDLER_CLEANUP, cleanup_body);
}
ADDOP_JREL(c, JUMP_FORWARD, end);
compiler_use_next_block(c, except);
@@ -2964,18 +3101,7 @@ compiler_visit_stmt(struct compiler *c, stmt_ty s)
case ClassDef_kind:
return compiler_class(c, s);
case Return_kind:
- if (c->u->u_ste->ste_type != FunctionBlock)
- return compiler_error(c, "'return' outside function");
- if (s->v.Return.value) {
- if (c->u->u_ste->ste_coroutine && c->u->u_ste->ste_generator)
- return compiler_error(
- c, "'return' with value in async generator");
- VISIT(c, expr, s->v.Return.value);
- }
- else
- ADDOP_O(c, LOAD_CONST, Py_None, consts);
- ADDOP(c, RETURN_VALUE);
- break;
+ return compiler_return(c, s);
case Delete_kind:
VISIT_SEQ(c, expr, s->v.Delete.targets)
break;
@@ -3027,10 +3153,7 @@ compiler_visit_stmt(struct compiler *c, stmt_ty s)
case Pass_kind:
break;
case Break_kind:
- if (!compiler_in_loop(c))
- return compiler_error(c, "'break' outside loop");
- ADDOP(c, BREAK_LOOP);
- break;
+ return compiler_break(c);
case Continue_kind:
return compiler_continue(c);
case With_kind:
@@ -3771,8 +3894,6 @@ compiler_call_helper(struct compiler *c,
The LC/SC version returns the populated container, while the GE version is
flagged in symtable.c as a generator, so it returns the generator object
when the function is called.
- This code *knows* that the loop cannot contain break, continue, or return,
- so it cheats and skips the SETUP_LOOP/POP_BLOCK steps used in normal loops.
Possible cleanups:
- iterate over the generator sequence instead of using recursion
@@ -3932,8 +4053,8 @@ compiler_async_comprehension_generator(struct compiler *c,
compiler_use_next_block(c, try);
- ADDOP_JREL(c, SETUP_EXCEPT, except);
- if (!compiler_push_fblock(c, EXCEPT, try))
+ ADDOP_JREL(c, SETUP_FINALLY, except);
+ if (!compiler_push_fblock(c, EXCEPT, try, NULL))
return 0;
ADDOP(c, GET_ANEXT);
@@ -3954,7 +4075,7 @@ compiler_async_comprehension_generator(struct compiler *c,
ADDOP(c, POP_TOP);
ADDOP(c, POP_TOP);
ADDOP(c, POP_TOP);
- ADDOP(c, POP_EXCEPT); /* for SETUP_EXCEPT */
+ ADDOP(c, POP_EXCEPT); /* for SETUP_FINALLY */
ADDOP_JABS(c, JUMP_ABSOLUTE, anchor);
@@ -4246,7 +4367,7 @@ compiler_async_with(struct compiler *c, stmt_ty s, int pos)
/* SETUP_ASYNC_WITH pushes a finally block. */
compiler_use_next_block(c, block);
- if (!compiler_push_fblock(c, FINALLY_TRY, block)) {
+ if (!compiler_push_fblock(c, ASYNC_WITH, block, finally)) {
return 0;
}
@@ -4267,11 +4388,11 @@ compiler_async_with(struct compiler *c, stmt_ty s, int pos)
/* End of try block; start the finally block */
ADDOP(c, POP_BLOCK);
- compiler_pop_fblock(c, FINALLY_TRY, block);
+ ADDOP(c, BEGIN_FINALLY);
+ compiler_pop_fblock(c, ASYNC_WITH, block);
- ADDOP_O(c, LOAD_CONST, Py_None, consts);
compiler_use_next_block(c, finally);
- if (!compiler_push_fblock(c, FINALLY_END, finally))
+ if (!compiler_push_fblock(c, FINALLY_END, finally, NULL))
return 0;
/* Finally block starts; context.__exit__ is on the stack under
@@ -4334,7 +4455,7 @@ compiler_with(struct compiler *c, stmt_ty s, int pos)
/* SETUP_WITH pushes a finally block. */
compiler_use_next_block(c, block);
- if (!compiler_push_fblock(c, FINALLY_TRY, block)) {
+ if (!compiler_push_fblock(c, WITH, block, finally)) {
return 0;
}
@@ -4355,11 +4476,11 @@ compiler_with(struct compiler *c, stmt_ty s, int pos)
/* End of try block; start the finally block */
ADDOP(c, POP_BLOCK);
- compiler_pop_fblock(c, FINALLY_TRY, block);
+ ADDOP(c, BEGIN_FINALLY);
+ compiler_pop_fblock(c, WITH, block);
- ADDOP_O(c, LOAD_CONST, Py_None, consts);
compiler_use_next_block(c, finally);
- if (!compiler_push_fblock(c, FINALLY_END, finally))
+ if (!compiler_push_fblock(c, FINALLY_END, finally, NULL))
return 0;
/* Finally block starts; context.__exit__ is on the stack under
@@ -4745,41 +4866,6 @@ compiler_annassign(struct compiler *c, stmt_ty s)
return 1;
}
-static int
-compiler_push_fblock(struct compiler *c, enum fblocktype t, basicblock *b)
-{
- struct fblockinfo *f;
- if (c->u->u_nfblocks >= CO_MAXBLOCKS) {
- PyErr_SetString(PyExc_SyntaxError,
- "too many statically nested blocks");
- return 0;
- }
- f = &c->u->u_fblock[c->u->u_nfblocks++];
- f->fb_type = t;
- f->fb_block = b;
- return 1;
-}
-
-static void
-compiler_pop_fblock(struct compiler *c, enum fblocktype t, basicblock *b)
-{
- struct compiler_unit *u = c->u;
- assert(u->u_nfblocks > 0);
- u->u_nfblocks--;
- assert(u->u_fblock[u->u_nfblocks].fb_type == t);
- assert(u->u_fblock[u->u_nfblocks].fb_block == b);
-}
-
-static int
-compiler_in_loop(struct compiler *c) {
- int i;
- struct compiler_unit *u = c->u;
- for (i = 0; i < u->u_nfblocks; ++i) {
- if (u->u_fblock[i].fb_type == LOOP)
- return 1;
- }
- return 0;
-}
/* Raises a SyntaxError and returns 0.
If something goes wrong, a different exception may be raised.
*/
@@ -4974,9 +5060,7 @@ dfs(struct compiler *c, basicblock *b, struct assembler *a, int end)
Py_LOCAL_INLINE(void)
stackdepth_push(basicblock ***sp, basicblock *b, int depth)
{
- /* XXX b->b_startdepth > depth only for the target of SETUP_FINALLY,
- * SETUP_WITH and SETUP_ASYNC_WITH. */
- assert(b->b_startdepth < 0 || b->b_startdepth >= depth);
+ assert(b->b_startdepth < 0 || b->b_startdepth == depth);
if (b->b_startdepth < depth) {
assert(b->b_startdepth < 0);
b->b_startdepth = depth;
@@ -5033,15 +5117,11 @@ stackdepth(struct compiler *c)
maxdepth = target_depth;
}
assert(target_depth >= 0); /* invalid code or bug in stackdepth() */
- if (instr->i_opcode == CONTINUE_LOOP) {
- /* Pops a variable number of values from the stack,
- * but the target should be already proceeding.
- */
+ if (instr->i_opcode == CALL_FINALLY) {
assert(instr->i_target->b_startdepth >= 0);
- assert(instr->i_target->b_startdepth <= depth);
- /* remaining code is dead */
- next = NULL;
- break;
+ assert(instr->i_target->b_startdepth >= target_depth);
+ depth = new_depth;
+ continue;
}
stackdepth_push(&sp, instr->i_target, target_depth);
}
@@ -5049,8 +5129,7 @@ stackdepth(struct compiler *c)
if (instr->i_opcode == JUMP_ABSOLUTE ||
instr->i_opcode == JUMP_FORWARD ||
instr->i_opcode == RETURN_VALUE ||
- instr->i_opcode == RAISE_VARARGS ||
- instr->i_opcode == BREAK_LOOP)
+ instr->i_opcode == RAISE_VARARGS)
{
/* remaining code is dead */
next = NULL;