summaryrefslogtreecommitdiffstats
path: root/Python/compile.c
diff options
context:
space:
mode:
Diffstat (limited to 'Python/compile.c')
-rw-r--r--Python/compile.c158
1 files changed, 58 insertions, 100 deletions
diff --git a/Python/compile.c b/Python/compile.c
index 1ab315b..bdafd92 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -6,9 +6,10 @@
* object:
* 1. Checks for future statements. See future.c
* 2. Builds a symbol table. See symtable.c.
- * 3. Generate code for basic blocks. See compiler_mod() in this file.
+ * 3. Generate code for basic blocks. See compiler_mod() in this file.
* 4. Assemble the basic blocks into final code. See assemble() in
- * this file.
+ * this file.
+ * 5. Optimize the byte code (peephole optimizations). See peephole.c
*
* Note that compiler_mod() suggests module, but the module ast type
* (mod_ty) has cases for expressions and interactive statements.
@@ -16,7 +17,8 @@
* CAUTION: The VISIT_* macros abort the current function when they
* encounter a problem. So don't invoke them when there is memory
* which needs to be released. Code blocks are OK, as the compiler
- * structure takes care of releasing those.
+ * structure takes care of releasing those. Use the arena to manage
+ * objects.
*/
#include "Python.h"
@@ -32,16 +34,6 @@
int Py_OptimizeFlag = 0;
-/*
- ISSUES:
-
- opcode_stack_effect() function should be reviewed since stack depth bugs
- could be really hard to find later.
-
- Dead code is being generated (i.e. after unconditional jumps).
- XXX(nnorwitz): not sure this is still true
-*/
-
#define DEFAULT_BLOCK_SIZE 16
#define DEFAULT_BLOCKS 8
#define DEFAULT_CODE_SIZE 128
@@ -116,11 +108,11 @@ struct compiler_unit {
int u_argcount; /* number of arguments for block */
int u_kwonlyargcount; /* number of keyword only arguments for block */
- /* Pointer to the most recently allocated block. By following b_list
- members, you can reach all early allocated blocks. */
+ /* Pointer to the most recently allocated block. By following b_list
+ members, you can reach all early allocated blocks. */
basicblock *u_blocks;
basicblock *u_curblock; /* pointer to current block */
- int u_tmpname; /* temporary variables for list comps */
+ int u_tmpname; /* temporary variables for list comps */
int u_nfblocks;
struct fblockinfo u_fblock[CO_MAXBLOCKS];
@@ -153,17 +145,6 @@ struct compiler {
PyArena *c_arena; /* pointer to memory allocation arena */
};
-struct assembler {
- PyObject *a_bytecode; /* string containing bytecode */
- int a_offset; /* offset into bytecode */
- int a_nblocks; /* number of reachable blocks */
- basicblock **a_postorder; /* list of blocks in dfs postorder */
- PyObject *a_lnotab; /* string containing lnotab */
- int a_lnotab_off; /* offset into lnotab */
- int a_lineno; /* last lineno of emitted instruction */
- int a_lineno_off; /* bytecode offset of last lineno */
-};
-
static int compiler_enter_scope(struct compiler *, identifier, void *, int);
static void compiler_free(struct compiler *);
static basicblock *compiler_new_block(struct compiler *);
@@ -188,6 +169,8 @@ 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 e);
@@ -395,47 +378,6 @@ dictbytype(PyObject *src, int scope_type, int flag, int offset)
return dest;
}
-/*
-
-Leave this debugging code for just a little longer.
-
-static void
-compiler_display_symbols(PyObject *name, PyObject *symbols)
-{
-PyObject *key, *value;
-int flags;
-Py_ssize_t pos = 0;
-
-fprintf(stderr, "block %s\n", PyString_AS_STRING(name));
-while (PyDict_Next(symbols, &pos, &key, &value)) {
-flags = PyInt_AsLong(value);
-fprintf(stderr, "var %s:", PyString_AS_STRING(key));
-if (flags & DEF_GLOBAL)
-fprintf(stderr, " declared_global");
-if (flags & DEF_LOCAL)
-fprintf(stderr, " local");
-if (flags & DEF_PARAM)
-fprintf(stderr, " param");
-if (flags & DEF_STAR)
-fprintf(stderr, " stararg");
-if (flags & DEF_DOUBLESTAR)
-fprintf(stderr, " starstar");
-if (flags & DEF_INTUPLE)
-fprintf(stderr, " tuple");
-if (flags & DEF_FREE)
-fprintf(stderr, " free");
-if (flags & DEF_FREE_GLOBAL)
-fprintf(stderr, " global");
-if (flags & DEF_FREE_CLASS)
-fprintf(stderr, " free/class");
-if (flags & DEF_IMPORT)
-fprintf(stderr, " import");
-fprintf(stderr, "\n");
-}
- fprintf(stderr, "\n");
-}
-*/
-
static void
compiler_unit_check(struct compiler_unit *u)
{
@@ -610,7 +552,7 @@ compiler_new_block(struct compiler *c)
return NULL;
}
memset((void *)b, 0, sizeof(basicblock));
- /* Extend the singly linked list of blocks with new block. */
+ /* Extend the singly linked list of blocks with new block. */
b->b_list = u->u_blocks;
u->u_blocks = b;
return b;
@@ -649,7 +591,7 @@ compiler_use_next_block(struct compiler *c, basicblock *block)
/* Returns the offset of the next instruction in the current block's
b_instr array. Resizes the b_instr as necessary.
Returns -1 on failure.
- */
+*/
static int
compiler_next_instr(struct compiler *c, basicblock *b)
@@ -693,7 +635,7 @@ compiler_next_instr(struct compiler *c, basicblock *b)
already been set. If it has been set, the call has no effect.
Every time a new node is b
- */
+*/
static void
compiler_set_lineno(struct compiler *c, int off)
@@ -1053,8 +995,8 @@ compiler_addop_j(struct compiler *c, int opcode, basicblock *b, int absolute)
from the current block to the new block.
*/
-/* XXX The returns inside these macros make it impossible to decref
- objects created in the local function.
+/* The returns inside these macros make it impossible to decref objects
+ created in the local function. Local objects should use the arena.
*/
@@ -1722,6 +1664,8 @@ static int
compiler_continue(struct compiler *c)
{
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;
if (!c->u->u_nfblocks)
@@ -1733,15 +1677,18 @@ compiler_continue(struct compiler *c)
break;
case EXCEPT:
case FINALLY_TRY:
- while (--i >= 0 && c->u->u_fblock[i].fb_type != LOOP)
- ;
+ 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,
- "'continue' not supported inside 'finally' clause");
+ return compiler_error(c, IN_FINALLY_ERROR_MSG);
}
return 1;
@@ -2084,7 +2031,7 @@ compiler_visit_stmt(struct compiler *c, stmt_ty s)
{
int i, n;
- /* Always assign a lineno to the next instruction for a stmt. */
+ /* Always assign a lineno to the next instruction for a stmt. */
c->u->u_lineno = s->lineno;
c->u->u_lineno_set = false;
@@ -2168,7 +2115,7 @@ compiler_visit_stmt(struct compiler *c, stmt_ty s)
case Pass_kind:
break;
case Break_kind:
- if (!c->u->u_nfblocks)
+ if (!compiler_in_loop(c))
return compiler_error(c, "'break' outside loop");
ADDOP(c, BREAK_LOOP);
break;
@@ -2522,7 +2469,6 @@ compiler_compare(struct compiler *c, expr_ty e)
}
return 1;
}
-#undef CMPCAST
static int
compiler_call(struct compiler *c, expr_ty e)
@@ -2622,7 +2568,7 @@ compiler_listcomp_generator(struct compiler *c, PyObject *tmpname,
}
ADDOP_JABS(c, JUMP_ABSOLUTE, start);
compiler_use_next_block(c, anchor);
- /* delete the append method added to locals */
+ /* delete the temporary list name added to locals */
if (gen_index == 1)
if (!compiler_nameop(c, tmpname, Del))
return 0;
@@ -2635,15 +2581,9 @@ compiler_listcomp(struct compiler *c, expr_ty e)
{
identifier tmp;
int rc = 0;
- static identifier append;
asdl_seq *generators = e->v.ListComp.generators;
assert(e->kind == ListComp_kind);
- if (!append) {
- append = PyString_InternFromString("append");
- if (!append)
- return 0;
- }
tmp = compiler_new_tmpname(c);
if (!tmp)
return 0;
@@ -2944,9 +2884,9 @@ compiler_visit_expr(struct compiler *c, expr_ty e)
{
int i, n;
- /* If expr e has a different line number than the last expr/stmt,
- set a new line number for the next instruction.
- */
+ /* If expr e has a different line number than the last expr/stmt,
+ set a new line number for the next instruction.
+ */
if (e->lineno > c->u->u_lineno) {
c->u->u_lineno = e->lineno;
c->u->u_lineno_set = false;
@@ -2995,14 +2935,6 @@ compiler_visit_expr(struct compiler *c, expr_ty e)
case Yield_kind:
if (c->u->u_ste->ste_type != FunctionBlock)
return compiler_error(c, "'yield' outside function");
- /*
- for (i = 0; i < c->u->u_nfblocks; i++) {
- if (c->u->u_fblock[i].fb_type == FINALLY_TRY)
- return compiler_error(
- c, "'yield' not allowed in a 'try' "
- "block with a 'finally' clause");
- }
- */
if (e->v.Yield.value) {
VISIT(c, expr, e->v.Yield.value);
}
@@ -3140,8 +3072,11 @@ static int
compiler_push_fblock(struct compiler *c, enum fblocktype t, basicblock *b)
{
struct fblockinfo *f;
- if (c->u->u_nfblocks >= CO_MAXBLOCKS)
+ if (c->u->u_nfblocks >= CO_MAXBLOCKS) {
+ PyErr_SetString(PyExc_SystemError,
+ "too many statically nested blocks");
return 0;
+ }
f = &c->u->u_fblock[c->u->u_nfblocks++];
f->fb_type = t;
f->fb_block = b;
@@ -3158,6 +3093,16 @@ compiler_pop_fblock(struct compiler *c, enum fblocktype t, basicblock *b)
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.
*/
@@ -3316,7 +3261,6 @@ compiler_visit_nested_slice(struct compiler *c, slice_ty s,
return 1;
}
-
static int
compiler_visit_slice(struct compiler *c, slice_ty s, expr_context_ty ctx)
{
@@ -3358,12 +3302,26 @@ compiler_visit_slice(struct compiler *c, slice_ty s, expr_context_ty ctx)
return compiler_handle_subscr(c, kindname, ctx);
}
+
+/* End of the compiler section, beginning of the assembler section */
+
/* do depth-first search of basic block graph, starting with block.
post records the block indices in post-order.
XXX must handle implicit jumps from one block to next
*/
+struct assembler {
+ PyObject *a_bytecode; /* string containing bytecode */
+ int a_offset; /* offset into bytecode */
+ int a_nblocks; /* number of reachable blocks */
+ basicblock **a_postorder; /* list of blocks in dfs postorder */
+ PyObject *a_lnotab; /* string containing lnotab */
+ int a_lnotab_off; /* offset into lnotab */
+ int a_lineno; /* last lineno of emitted instruction */
+ int a_lineno_off; /* bytecode offset of last lineno */
+};
+
static void
dfs(struct compiler *c, basicblock *b, struct assembler *a)
{