summaryrefslogtreecommitdiffstats
path: root/Python
diff options
context:
space:
mode:
authorIrit Katriel <1055913+iritkatriel@users.noreply.github.com>2022-11-14 13:56:40 (GMT)
committerGitHub <noreply@github.com>2022-11-14 13:56:40 (GMT)
commita3ac9232f859a144b5e1db494dbb928e0cd169ab (patch)
tree961e093bd549b81bf1311e3129b9305587bd26e9 /Python
parent06d4e02c3b3526b5d90e41a0a0befa8663e08f27 (diff)
downloadcpython-a3ac9232f859a144b5e1db494dbb928e0cd169ab.zip
cpython-a3ac9232f859a144b5e1db494dbb928e0cd169ab.tar.gz
cpython-a3ac9232f859a144b5e1db494dbb928e0cd169ab.tar.bz2
gh-87092: expose the compiler's codegen to python for unit tests (GH-99111)
Diffstat (limited to 'Python')
-rw-r--r--Python/compile.c173
1 files changed, 120 insertions, 53 deletions
diff --git a/Python/compile.c b/Python/compile.c
index 37f3b23..bd41ebc 100644
--- a/Python/compile.c
+++ b/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)
+compiler_setup(struct compiler *c, mod_ty mod, PyObject *filename,
+ PyCompilerFlags flags, int optimize, PyArena *arena)
{
- memset(c, 0, sizeof(struct compiler));
-
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;
- }
- if (!flags) {
- flags = &local_flags;
+ c->c_filename = Py_NewRef(filename);
+ c->c_arena = arena;
+ if (!_PyFuture_FromAST(mod, filename, &c->c_future)) {
+ return 0;
}
- 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;
+}
- co = compiler_mod(&c, mod);
+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;
+}
- finally:
- compiler_free(&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;
+ }
+
+ 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 &&
@@ -9860,6 +9876,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)