diff options
Diffstat (limited to 'Python/compile.c')
-rw-r--r-- | Python/compile.c | 158 |
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) { |