diff options
author | Mark Shannon <mark@hotpy.org> | 2020-11-12 09:43:29 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-11-12 09:43:29 (GMT) |
commit | 877df851c3ecdb55306840e247596e7b7805a60a (patch) | |
tree | ec00c0af84f9f228d78e23e8c8b38201129f8fae /Python/compile.c | |
parent | cda99b4022daa08ac74b0420e9903cce883d91c6 (diff) | |
download | cpython-877df851c3ecdb55306840e247596e7b7805a60a.zip cpython-877df851c3ecdb55306840e247596e7b7805a60a.tar.gz cpython-877df851c3ecdb55306840e247596e7b7805a60a.tar.bz2 |
bpo-42246: Partial implementation of PEP 626. (GH-23113)
* Implement new line number table format, as defined in PEP 626.
Diffstat (limited to 'Python/compile.c')
-rw-r--r-- | Python/compile.c | 202 |
1 files changed, 103 insertions, 99 deletions
diff --git a/Python/compile.c b/Python/compile.c index 15a9046..b4f2ceb 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -1827,7 +1827,7 @@ compiler_mod(struct compiler *c, mod_ty mod) return NULL; } /* Use 0 for firstlineno initially, will fixup in assemble(). */ - if (!compiler_enter_scope(c, module, COMPILER_SCOPE_MODULE, mod, 0)) + if (!compiler_enter_scope(c, module, COMPILER_SCOPE_MODULE, mod, 1)) return NULL; switch (mod->kind) { case Module_kind: @@ -2271,7 +2271,9 @@ compiler_function(struct compiler *c, stmt_ty s, int is_async) c->u->u_argcount = asdl_seq_LEN(args->args); c->u->u_posonlyargcount = asdl_seq_LEN(args->posonlyargs); c->u->u_kwonlyargcount = asdl_seq_LEN(args->kwonlyargs); - VISIT_SEQ_IN_SCOPE(c, stmt, body); + for (i = docstring ? 1 : 0; i < asdl_seq_LEN(body); i++) { + VISIT(c, stmt, (stmt_ty)asdl_seq_GET(body, i)); + } co = assemble(c, 1); qualname = c->u->u_qualname; Py_INCREF(qualname); @@ -2808,6 +2810,8 @@ compiler_async_for(struct compiler *c, stmt_ty s) /* Except block for __anext__ */ compiler_use_next_block(c, except); + + c->u->u_lineno = -1; ADDOP(c, END_ASYNC_FOR); /* `else` block */ @@ -3115,7 +3119,8 @@ compiler_try_except(struct compiler *c, stmt_ty s) compiler_pop_fblock(c, HANDLER_CLEANUP, cleanup_body); ADDOP(c, POP_BLOCK); ADDOP(c, POP_EXCEPT); - /* name = None; del name */ + /* name = None; del name; # Mark as artificial */ + c->u->u_lineno = -1; ADDOP_LOAD_CONST(c, Py_None); compiler_nameop(c, handler->v.ExceptHandler.name, Store); compiler_nameop(c, handler->v.ExceptHandler.name, Del); @@ -3124,7 +3129,8 @@ compiler_try_except(struct compiler *c, stmt_ty s) /* except: */ compiler_use_next_block(c, cleanup_end); - /* name = None; del name */ + /* name = None; del name; # Mark as artificial */ + c->u->u_lineno = -1; ADDOP_LOAD_CONST(c, Py_None); compiler_nameop(c, handler->v.ExceptHandler.name, Store); compiler_nameop(c, handler->v.ExceptHandler.name, Del); @@ -3359,6 +3365,7 @@ compiler_visit_stmt_expr(struct compiler *c, expr_ty value) if (value->kind == Constant_kind) { /* ignore constant statement */ + ADDOP(c, NOP); return 1; } @@ -3431,6 +3438,7 @@ compiler_visit_stmt(struct compiler *c, stmt_ty s) case Expr_kind: return compiler_visit_stmt_expr(c, s->v.Expr.value); case Pass_kind: + ADDOP(c, NOP); break; case Break_kind: return compiler_break(c); @@ -5429,8 +5437,9 @@ struct assembler { basicblock **a_reverse_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 */ + int a_prevlineno; /* lineno of last emitted line in line table */ + int a_lineno; /* lineno of last emitted instruction */ + int a_lineno_start; /* bytecode start offset of current lineno */ }; static void @@ -5533,7 +5542,7 @@ static int assemble_init(struct assembler *a, int nblocks, int firstlineno) { memset(a, 0, sizeof(struct assembler)); - a->a_lineno = firstlineno; + a->a_prevlineno = a->a_lineno = firstlineno; a->a_bytecode = PyBytes_FromStringAndSize(NULL, DEFAULT_CODE_SIZE); if (!a->a_bytecode) return 0; @@ -5573,114 +5582,82 @@ blocksize(basicblock *b) return size; } -/* Appends a pair to the end of the line number table, a_lnotab, representing - the instruction's bytecode offset and line number. See - Objects/lnotab_notes.txt for the description of the line number table. */ - static int -assemble_lnotab(struct assembler *a, struct instr *i) +assemble_emit_linetable_pair(struct assembler *a, int bdelta, int ldelta) { - int d_bytecode, d_lineno; - Py_ssize_t len; - unsigned char *lnotab; - - d_lineno = i->i_lineno - a->a_lineno; - if (d_lineno == 0) { - return 1; + Py_ssize_t len = PyBytes_GET_SIZE(a->a_lnotab); + if (a->a_lnotab_off + 2 >= len) { + if (_PyBytes_Resize(&a->a_lnotab, len * 2) < 0) + return 0; } + unsigned char *lnotab = (unsigned char *) + PyBytes_AS_STRING(a->a_lnotab) + a->a_lnotab_off; + + a->a_lnotab_off += 2; + *lnotab++ = bdelta; + *lnotab++ = ldelta; + return 1; +} - d_bytecode = (a->a_offset - a->a_lineno_off) * sizeof(_Py_CODEUNIT); - assert(d_bytecode >= 0); +/* Appends a range to the end of the line number table. See + * Objects/lnotab_notes.txt for the description of the line number table. */ - if (d_bytecode > 255) { - int j, nbytes, ncodes = d_bytecode / 255; - nbytes = a->a_lnotab_off + 2 * ncodes; - len = PyBytes_GET_SIZE(a->a_lnotab); - if (nbytes >= len) { - if ((len <= INT_MAX / 2) && (len * 2 < nbytes)) - len = nbytes; - else if (len <= INT_MAX / 2) - len *= 2; - else { - PyErr_NoMemory(); +static int +assemble_line_range(struct assembler *a) +{ + int ldelta, bdelta; + bdelta = (a->a_offset - a->a_lineno_start) * 2; + if (bdelta == 0) { + return 1; + } + if (a->a_lineno < 0) { + ldelta = -128; + } + else { + ldelta = a->a_lineno - a->a_prevlineno; + a->a_prevlineno = a->a_lineno; + while (ldelta > 127) { + if (!assemble_emit_linetable_pair(a, 0, 127)) { return 0; } - if (_PyBytes_Resize(&a->a_lnotab, len) < 0) - return 0; - } - lnotab = (unsigned char *) - PyBytes_AS_STRING(a->a_lnotab) + a->a_lnotab_off; - for (j = 0; j < ncodes; j++) { - *lnotab++ = 255; - *lnotab++ = 0; + ldelta -= 127; } - d_bytecode -= ncodes * 255; - a->a_lnotab_off += ncodes * 2; - } - assert(0 <= d_bytecode && d_bytecode <= 255); - - if (d_lineno < -128 || 127 < d_lineno) { - int j, nbytes, ncodes, k; - if (d_lineno < 0) { - k = -128; - /* use division on positive numbers */ - ncodes = (-d_lineno) / 128; - } - else { - k = 127; - ncodes = d_lineno / 127; - } - d_lineno -= ncodes * k; - assert(ncodes >= 1); - nbytes = a->a_lnotab_off + 2 * ncodes; - len = PyBytes_GET_SIZE(a->a_lnotab); - if (nbytes >= len) { - if ((len <= INT_MAX / 2) && len * 2 < nbytes) - len = nbytes; - else if (len <= INT_MAX / 2) - len *= 2; - else { - PyErr_NoMemory(); + while (ldelta < -127) { + if (!assemble_emit_linetable_pair(a, 0, -127)) { return 0; } - if (_PyBytes_Resize(&a->a_lnotab, len) < 0) - return 0; + ldelta += 127; } - lnotab = (unsigned char *) - PyBytes_AS_STRING(a->a_lnotab) + a->a_lnotab_off; - *lnotab++ = d_bytecode; - *lnotab++ = k; - d_bytecode = 0; - for (j = 1; j < ncodes; j++) { - *lnotab++ = 0; - *lnotab++ = k; - } - a->a_lnotab_off += ncodes * 2; } - assert(-128 <= d_lineno && d_lineno <= 127); - - len = PyBytes_GET_SIZE(a->a_lnotab); - if (a->a_lnotab_off + 2 >= len) { - if (_PyBytes_Resize(&a->a_lnotab, len * 2) < 0) + assert(-128 <= ldelta && ldelta < 128); + while (bdelta > 254) { + if (!assemble_emit_linetable_pair(a, 254, ldelta)) { return 0; + } + ldelta = a->a_lineno < 0 ? -128 : 0; + bdelta -= 254; } - lnotab = (unsigned char *) - PyBytes_AS_STRING(a->a_lnotab) + a->a_lnotab_off; + if (!assemble_emit_linetable_pair(a, bdelta, ldelta)) { + return 0; + } + a->a_lineno_start = a->a_offset; + return 1; +} - a->a_lnotab_off += 2; - if (d_bytecode) { - *lnotab++ = d_bytecode; - *lnotab++ = d_lineno; +static int +assemble_lnotab(struct assembler *a, struct instr *i) +{ + if (i->i_lineno == a->a_lineno) { + return 1; } - else { /* First line of a block; def stmt, etc. */ - *lnotab++ = 0; - *lnotab++ = d_lineno; + if (!assemble_line_range(a)) { + return 0; } a->a_lineno = i->i_lineno; - a->a_lineno_off = a->a_offset; return 1; } + /* assemble_emit() Extend the bytecode with a new instruction. Update lnotab if necessary. @@ -5998,7 +5975,7 @@ assemble(struct compiler *c, int addNone) block ends with a jump or return b_next shouldn't set. */ if (!c->u->u_curblock->b_return) { - NEXT_BLOCK(c); + c->u->u_lineno = -1; if (addNone) ADDOP_LOAD_CONST(c, Py_None); ADDOP(c, RETURN_VALUE); @@ -6015,7 +5992,7 @@ assemble(struct compiler *c, int addNone) if (!c->u->u_firstlineno) { if (entryblock && entryblock->b_instr && entryblock->b_instr->i_lineno) c->u->u_firstlineno = entryblock->b_instr->i_lineno; - else + else c->u->u_firstlineno = 1; } if (!assemble_init(&a, nblocks, c->u->u_firstlineno)) @@ -6040,6 +6017,13 @@ assemble(struct compiler *c, int addNone) if (!assemble_emit(&a, &b->b_instr[j])) goto error; } + if (!assemble_line_range(&a)) { + return 0; + } + /* Emit sentinel at end of line number table */ + if (!assemble_emit_linetable_pair(&a, 255, -128)) { + goto error; + } if (_PyBytes_Resize(&a.a_lnotab, a.a_lnotab_off) < 0) goto error; @@ -6280,22 +6264,42 @@ static void clean_basic_block(basicblock *bb) { /* Remove NOPs and any code following a return or re-raise. */ int dest = 0; + int prev_lineno = -1; for (int src = 0; src < bb->b_iused; src++) { + int lineno = bb->b_instr[src].i_lineno; switch(bb->b_instr[src].i_opcode) { - case NOP: - /* skip */ - break; case RETURN_VALUE: case RERAISE: bb->b_next = NULL; bb->b_instr[dest] = bb->b_instr[src]; dest++; goto end; + case NOP: + { + /* Eliminate no-op if it doesn't have a line number, or + * if the next instruction has same line number or no line number, or + * if the previous instruction had the same line number. */ + if (lineno < 0) { + break; + } + if (prev_lineno == lineno) { + break; + } + if (src < bb->b_iused - 1) { + int next_lineno = bb->b_instr[src+1].i_lineno; + if (next_lineno < 0 || next_lineno == lineno) { + bb->b_instr[src+1].i_lineno = lineno; + break; + } + } + } + /* fallthrough */ default: if (dest != src) { bb->b_instr[dest] = bb->b_instr[src]; } dest++; + prev_lineno = lineno; break; } } |