mirror of
https://github.com/python/cpython.git
synced 2025-07-19 17:25:54 +00:00
gh-87092: expose the compiler's codegen to python for unit tests (GH-99111)
This commit is contained in:
parent
06d4e02c3b
commit
a3ac9232f8
11 changed files with 323 additions and 99 deletions
177
Python/compile.c
177
Python/compile.c
|
@ -122,7 +122,7 @@
|
|||
(opcode) == STORE_FAST__STORE_FAST)
|
||||
|
||||
#define IS_TOP_LEVEL_AWAIT(c) ( \
|
||||
(c->c_flags->cf_flags & PyCF_ALLOW_TOP_LEVEL_AWAIT) \
|
||||
(c->c_flags.cf_flags & PyCF_ALLOW_TOP_LEVEL_AWAIT) \
|
||||
&& (c->u->u_ste->ste_type == ModuleBlock))
|
||||
|
||||
typedef _PyCompilerSrcLocation location;
|
||||
|
@ -418,7 +418,7 @@ struct compiler {
|
|||
PyObject *c_filename;
|
||||
struct symtable *c_st;
|
||||
PyFutureFeatures c_future; /* module's __future__ */
|
||||
PyCompilerFlags *c_flags;
|
||||
PyCompilerFlags c_flags;
|
||||
|
||||
int c_optimize; /* optimization level */
|
||||
int c_interactive; /* true if in interactive mode */
|
||||
|
@ -583,11 +583,11 @@ _Py_Mangle(PyObject *privateobj, PyObject *ident)
|
|||
return result;
|
||||
}
|
||||
|
||||
static int
|
||||
compiler_init(struct compiler *c)
|
||||
{
|
||||
memset(c, 0, sizeof(struct compiler));
|
||||
|
||||
static int
|
||||
compiler_setup(struct compiler *c, mod_ty mod, PyObject *filename,
|
||||
PyCompilerFlags flags, int optimize, PyArena *arena)
|
||||
{
|
||||
c->c_const_cache = PyDict_New();
|
||||
if (!c->c_const_cache) {
|
||||
return 0;
|
||||
|
@ -595,57 +595,65 @@ compiler_init(struct compiler *c)
|
|||
|
||||
c->c_stack = PyList_New(0);
|
||||
if (!c->c_stack) {
|
||||
Py_CLEAR(c->c_const_cache);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
PyCodeObject *
|
||||
_PyAST_Compile(mod_ty mod, PyObject *filename, PyCompilerFlags *flags,
|
||||
int optimize, PyArena *arena)
|
||||
{
|
||||
struct compiler c;
|
||||
PyCodeObject *co = NULL;
|
||||
PyCompilerFlags local_flags = _PyCompilerFlags_INIT;
|
||||
int merged;
|
||||
if (!compiler_init(&c))
|
||||
return NULL;
|
||||
c.c_filename = Py_NewRef(filename);
|
||||
c.c_arena = arena;
|
||||
if (!_PyFuture_FromAST(mod, filename, &c.c_future)) {
|
||||
goto finally;
|
||||
c->c_filename = Py_NewRef(filename);
|
||||
c->c_arena = arena;
|
||||
if (!_PyFuture_FromAST(mod, filename, &c->c_future)) {
|
||||
return 0;
|
||||
}
|
||||
if (!flags) {
|
||||
flags = &local_flags;
|
||||
}
|
||||
merged = c.c_future.ff_features | flags->cf_flags;
|
||||
c.c_future.ff_features = merged;
|
||||
flags->cf_flags = merged;
|
||||
c.c_flags = flags;
|
||||
c.c_optimize = (optimize == -1) ? _Py_GetConfig()->optimization_level : optimize;
|
||||
c.c_nestlevel = 0;
|
||||
int merged = c->c_future.ff_features | flags.cf_flags;
|
||||
c->c_future.ff_features = merged;
|
||||
flags.cf_flags = merged;
|
||||
c->c_flags = flags;
|
||||
c->c_optimize = (optimize == -1) ? _Py_GetConfig()->optimization_level : optimize;
|
||||
c->c_nestlevel = 0;
|
||||
|
||||
_PyASTOptimizeState state;
|
||||
state.optimize = c.c_optimize;
|
||||
state.optimize = c->c_optimize;
|
||||
state.ff_features = merged;
|
||||
|
||||
if (!_PyAST_Optimize(mod, arena, &state)) {
|
||||
goto finally;
|
||||
return 0;
|
||||
}
|
||||
|
||||
c.c_st = _PySymtable_Build(mod, filename, &c.c_future);
|
||||
if (c.c_st == NULL) {
|
||||
if (!PyErr_Occurred())
|
||||
c->c_st = _PySymtable_Build(mod, filename, &c->c_future);
|
||||
if (c->c_st == NULL) {
|
||||
if (!PyErr_Occurred()) {
|
||||
PyErr_SetString(PyExc_SystemError, "no symtable");
|
||||
goto finally;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct compiler*
|
||||
new_compiler(mod_ty mod, PyObject *filename, PyCompilerFlags *pflags,
|
||||
int optimize, PyArena *arena)
|
||||
{
|
||||
PyCompilerFlags flags = pflags ? *pflags : _PyCompilerFlags_INIT;
|
||||
struct compiler *c = PyMem_Calloc(1, sizeof(struct compiler));
|
||||
if (c == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (!compiler_setup(c, mod, filename, flags, optimize, arena)) {
|
||||
compiler_free(c);
|
||||
return NULL;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
PyCodeObject *
|
||||
_PyAST_Compile(mod_ty mod, PyObject *filename, PyCompilerFlags *pflags,
|
||||
int optimize, PyArena *arena)
|
||||
{
|
||||
struct compiler *c = new_compiler(mod, filename, pflags, optimize, arena);
|
||||
if (c == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
co = compiler_mod(&c, mod);
|
||||
|
||||
finally:
|
||||
compiler_free(&c);
|
||||
PyCodeObject *co = compiler_mod(c, mod);
|
||||
compiler_free(c);
|
||||
assert(co || PyErr_Occurred());
|
||||
return co;
|
||||
}
|
||||
|
@ -656,8 +664,9 @@ compiler_free(struct compiler *c)
|
|||
if (c->c_st)
|
||||
_PySymtable_Free(c->c_st);
|
||||
Py_XDECREF(c->c_filename);
|
||||
Py_DECREF(c->c_const_cache);
|
||||
Py_DECREF(c->c_stack);
|
||||
Py_XDECREF(c->c_const_cache);
|
||||
Py_XDECREF(c->c_stack);
|
||||
PyMem_Free(c);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
|
@ -2136,15 +2145,13 @@ compiler_body(struct compiler *c, location loc, asdl_stmt_seq *stmts)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static PyCodeObject *
|
||||
compiler_mod(struct compiler *c, mod_ty mod)
|
||||
static int
|
||||
compiler_codegen(struct compiler *c, mod_ty mod)
|
||||
{
|
||||
PyCodeObject *co;
|
||||
int addNone = 1;
|
||||
_Py_DECLARE_STR(anon_module, "<module>");
|
||||
if (!compiler_enter_scope(c, &_Py_STR(anon_module), COMPILER_SCOPE_MODULE,
|
||||
mod, 1)) {
|
||||
return NULL;
|
||||
return 0;
|
||||
}
|
||||
location loc = LOCATION(1, 1, 0, 0);
|
||||
switch (mod->kind) {
|
||||
|
@ -2163,7 +2170,6 @@ compiler_mod(struct compiler *c, mod_ty mod)
|
|||
break;
|
||||
case Expression_kind:
|
||||
VISIT_IN_SCOPE(c, expr, mod->v.Expression.body);
|
||||
addNone = 0;
|
||||
break;
|
||||
default:
|
||||
PyErr_Format(PyExc_SystemError,
|
||||
|
@ -2171,7 +2177,17 @@ compiler_mod(struct compiler *c, mod_ty mod)
|
|||
mod->kind);
|
||||
return 0;
|
||||
}
|
||||
co = assemble(c, addNone);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static PyCodeObject *
|
||||
compiler_mod(struct compiler *c, mod_ty mod)
|
||||
{
|
||||
int addNone = mod->kind != Expression_kind;
|
||||
if (!compiler_codegen(c, mod)) {
|
||||
return NULL;
|
||||
}
|
||||
PyCodeObject *co = assemble(c, addNone);
|
||||
compiler_exit_scope(c);
|
||||
return co;
|
||||
}
|
||||
|
@ -8229,7 +8245,7 @@ compute_code_flags(struct compiler *c)
|
|||
}
|
||||
|
||||
/* (Only) inherit compilerflags in PyCF_MASK */
|
||||
flags |= (c->c_flags->cf_flags & PyCF_MASK);
|
||||
flags |= (c->c_flags.cf_flags & PyCF_MASK);
|
||||
|
||||
if ((IS_TOP_LEVEL_AWAIT(c)) &&
|
||||
ste->ste_coroutine &&
|
||||
|
@ -9859,6 +9875,9 @@ duplicate_exits_without_lineno(cfg_builder *g)
|
|||
|
||||
|
||||
/* Access to compiler optimizations for unit tests.
|
||||
*
|
||||
* _PyCompile_CodeGen takes and AST, applies code-gen and
|
||||
* returns the unoptimized CFG as an instruction list.
|
||||
*
|
||||
* _PyCompile_OptimizeCfg takes an instruction list, constructs
|
||||
* a CFG, optimizes it and converts back to an instruction list.
|
||||
|
@ -9954,7 +9973,9 @@ cfg_to_instructions(cfg_builder *g)
|
|||
for (int i = 0; i < b->b_iused; i++) {
|
||||
struct instr *instr = &b->b_instr[i];
|
||||
location loc = instr->i_loc;
|
||||
int arg = HAS_TARGET(instr->i_opcode) ? instr->i_target->b_label : instr->i_oparg;
|
||||
int arg = HAS_TARGET(instr->i_opcode) ?
|
||||
instr->i_target->b_label : instr->i_oparg;
|
||||
|
||||
PyObject *inst_tuple = Py_BuildValue(
|
||||
"(iiiiii)", instr->i_opcode, arg,
|
||||
loc.lineno, loc.end_lineno,
|
||||
|
@ -9977,6 +9998,52 @@ error:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
_PyCompile_CodeGen(PyObject *ast, PyObject *filename, PyCompilerFlags *pflags,
|
||||
int optimize)
|
||||
{
|
||||
PyObject *res = NULL;
|
||||
|
||||
if (!PyAST_Check(ast)) {
|
||||
PyErr_SetString(PyExc_TypeError, "expected an AST");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyArena *arena = _PyArena_New();
|
||||
if (arena == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mod_ty mod = PyAST_obj2mod(ast, arena, 0 /* exec */);
|
||||
if (mod == NULL || !_PyAST_Validate(mod)) {
|
||||
_PyArena_Free(arena);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct compiler *c = new_compiler(mod, filename, pflags, optimize, arena);
|
||||
if (c == NULL) {
|
||||
_PyArena_Free(arena);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!compiler_codegen(c, mod)) {
|
||||
goto finally;
|
||||
}
|
||||
|
||||
cfg_builder *g = CFG_BUILDER(c);
|
||||
|
||||
if (translate_jump_labels_to_targets(g->g_entryblock) < 0) {
|
||||
goto finally;
|
||||
}
|
||||
|
||||
res = cfg_to_instructions(g);
|
||||
|
||||
finally:
|
||||
compiler_exit_scope(c);
|
||||
compiler_free(c);
|
||||
_PyArena_Free(arena);
|
||||
return res;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
_PyCompile_OptimizeCfg(PyObject *instructions, PyObject *consts)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue