mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +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 @@ cfg_to_instructions(cfg_builder *g) | |||
|     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
	
	 Irit Katriel
						Irit Katriel