diff options
Diffstat (limited to 'contrib/tools/python3/Python/compile.c')
| -rw-r--r-- | contrib/tools/python3/Python/compile.c | 1509 |
1 files changed, 680 insertions, 829 deletions
diff --git a/contrib/tools/python3/Python/compile.c b/contrib/tools/python3/Python/compile.c index cc639ff64ff..8f8b6773440 100644 --- a/contrib/tools/python3/Python/compile.c +++ b/contrib/tools/python3/Python/compile.c @@ -22,25 +22,24 @@ */ #include "Python.h" +#include "opcode.h" #include "pycore_ast.h" // _PyAST_GetDocString() #define NEED_OPCODE_TABLES #include "pycore_opcode_utils.h" #undef NEED_OPCODE_TABLES -#include "pycore_flowgraph.h" #include "pycore_code.h" // _PyCode_New() #include "pycore_compile.h" +#include "pycore_flowgraph.h" +#include "pycore_instruction_sequence.h" // _PyInstructionSequence_New() #include "pycore_intrinsics.h" #include "pycore_long.h" // _PyLong_GetZero() -#include "pycore_pymem.h" // _PyMem_IsPtrFreed() +#include "pycore_pystate.h" // _Py_GetConfig() +#include "pycore_setobject.h" // _PySet_NextEntry() #include "pycore_symtable.h" // PySTEntryObject, _PyFuture_FromAST() -#include "opcode_metadata.h" // _PyOpcode_opcode_metadata, _PyOpcode_num_popped/pushed - -#include <stdbool.h> - -#define DEFAULT_CODE_SIZE 128 -#define DEFAULT_LNOTAB_SIZE 16 -#define DEFAULT_CNOTAB_SIZE 32 +#define NEED_OPCODE_METADATA +#include "pycore_opcode_metadata.h" // _PyOpcode_opcode_metadata, _PyOpcode_num_popped/pushed +#undef NEED_OPCODE_METADATA #define COMP_GENEXP 0 #define COMP_LISTCOMP 1 @@ -56,6 +55,8 @@ */ #define STACK_USE_GUIDELINE 30 +#include <stdbool.h> + #undef SUCCESS #undef ERROR #define SUCCESS 0 @@ -66,32 +67,15 @@ return ERROR; \ } -/* If we exceed this limit, it should - * be considered a compiler bug. - * Currently it should be impossible - * to exceed STACK_USE_GUIDELINE * 100, - * as 100 is the maximum parse depth. - * For performance reasons we will - * want to reduce this to a - * few hundred in the future. - * - * NOTE: Whatever MAX_ALLOWED_STACK_USE is - * set to, it should never restrict what Python - * we can write, just how we compile it. - */ -#define MAX_ALLOWED_STACK_USE (STACK_USE_GUIDELINE * 100) - #define IS_TOP_LEVEL_AWAIT(C) ( \ ((C)->c_flags.cf_flags & PyCF_ALLOW_TOP_LEVEL_AWAIT) \ && ((C)->u->u_ste->ste_type == ModuleBlock)) -typedef _PyCompilerSrcLocation location; -typedef _PyCfgInstruction cfg_instr; -typedef _PyCfgBasicblock basicblock; -typedef _PyCfgBuilder cfg_builder; +typedef _Py_SourceLocation location; +typedef struct _PyCfgBuilder cfg_builder; #define LOCATION(LNO, END_LNO, COL, END_COL) \ - ((const _PyCompilerSrcLocation){(LNO), (END_LNO), (COL), (END_COL)}) + ((const _Py_SourceLocation){(LNO), (END_LNO), (COL), (END_COL)}) /* Return true if loc1 starts after loc2 ends. */ static inline bool @@ -103,7 +87,7 @@ location_is_after(location loc1, location loc2) { #define LOC(x) SRC_LOCATION_FROM_AST(x) -typedef _PyCfgJumpTargetLabel jump_target_label; +typedef _PyJumpTargetLabel jump_target_label; static jump_target_label NO_LABEL = {-1}; @@ -111,13 +95,13 @@ static jump_target_label NO_LABEL = {-1}; #define IS_LABEL(L) (!SAME_LABEL((L), (NO_LABEL))) #define NEW_JUMP_TARGET_LABEL(C, NAME) \ - jump_target_label NAME = instr_sequence_new_label(INSTR_SEQUENCE(C)); \ + jump_target_label NAME = _PyInstructionSequence_NewLabel(INSTR_SEQUENCE(C)); \ if (!IS_LABEL(NAME)) { \ return ERROR; \ } #define USE_LABEL(C, LBL) \ - RETURN_IF_ERROR(instr_sequence_use_label(INSTR_SEQUENCE(C), (LBL).id)) + RETURN_IF_ERROR(_PyInstructionSequence_UseLabel(INSTR_SEQUENCE(C), (LBL).id)) /* fblockinfo tracks the current frame block. @@ -153,18 +137,8 @@ enum { }; -int -_PyCompile_InstrSize(int opcode, int oparg) -{ - assert(!IS_PSEUDO_OPCODE(opcode)); - assert(HAS_ARG(opcode) || oparg == 0); - int extended_args = (0xFFFFFF < oparg) + (0xFFFF < oparg) + (0xFF < oparg); - int caches = _PyOpcode_Caches[opcode]; - return extended_args + 1 + caches; -} - -typedef _PyCompile_Instruction instruction; -typedef _PyCompile_InstructionSequence instr_sequence; +typedef _PyInstruction instruction; +typedef _PyInstructionSequence instr_sequence; #define INITIAL_INSTR_SEQUENCE_SIZE 100 #define INITIAL_INSTR_SEQUENCE_LABELS_MAP_SIZE 10 @@ -189,7 +163,7 @@ _PyCompile_EnsureArrayLargeEnough(int idx, void **array, int *alloc, if (idx >= new_alloc) { new_alloc = idx + default_alloc; } - arr = PyObject_Calloc(new_alloc, item_size); + arr = PyMem_Calloc(new_alloc, item_size); if (arr == NULL) { PyErr_NoMemory(); return ERROR; @@ -210,7 +184,7 @@ _PyCompile_EnsureArrayLargeEnough(int idx, void **array, int *alloc, } assert(newsize > 0); - void *tmp = PyObject_Realloc(arr, newsize); + void *tmp = PyMem_Realloc(arr, newsize); if (tmp == NULL) { PyErr_NoMemory(); return ERROR; @@ -224,159 +198,48 @@ _PyCompile_EnsureArrayLargeEnough(int idx, void **array, int *alloc, return SUCCESS; } -static int -instr_sequence_next_inst(instr_sequence *seq) { - assert(seq->s_instrs != NULL || seq->s_used == 0); - - RETURN_IF_ERROR( - _PyCompile_EnsureArrayLargeEnough(seq->s_used + 1, - (void**)&seq->s_instrs, - &seq->s_allocated, - INITIAL_INSTR_SEQUENCE_SIZE, - sizeof(instruction))); - assert(seq->s_allocated >= 0); - assert(seq->s_used < seq->s_allocated); - return seq->s_used++; -} - -static jump_target_label -instr_sequence_new_label(instr_sequence *seq) -{ - jump_target_label lbl = {++seq->s_next_free_label}; - return lbl; -} - -static int -instr_sequence_use_label(instr_sequence *seq, int lbl) { - int old_size = seq->s_labelmap_size; - RETURN_IF_ERROR( - _PyCompile_EnsureArrayLargeEnough(lbl, - (void**)&seq->s_labelmap, - &seq->s_labelmap_size, - INITIAL_INSTR_SEQUENCE_LABELS_MAP_SIZE, - sizeof(int))); - - for(int i = old_size; i < seq->s_labelmap_size; i++) { - seq->s_labelmap[i] = -111; /* something weird, for debugging */ - } - seq->s_labelmap[lbl] = seq->s_used; /* label refers to the next instruction */ - return SUCCESS; -} - -static int -instr_sequence_addop(instr_sequence *seq, int opcode, int oparg, location loc) -{ - assert(IS_WITHIN_OPCODE_RANGE(opcode)); - assert(HAS_ARG(opcode) || HAS_TARGET(opcode) || oparg == 0); - assert(0 <= oparg && oparg < (1 << 30)); - - int idx = instr_sequence_next_inst(seq); - RETURN_IF_ERROR(idx); - instruction *ci = &seq->s_instrs[idx]; - ci->i_opcode = opcode; - ci->i_oparg = oparg; - ci->i_loc = loc; - return SUCCESS; -} - -static int -instr_sequence_insert_instruction(instr_sequence *seq, int pos, - int opcode, int oparg, location loc) -{ - assert(pos >= 0 && pos <= seq->s_used); - int last_idx = instr_sequence_next_inst(seq); - RETURN_IF_ERROR(last_idx); - for (int i=last_idx-1; i >= pos; i--) { - seq->s_instrs[i+1] = seq->s_instrs[i]; - } - instruction *ci = &seq->s_instrs[pos]; - ci->i_opcode = opcode; - ci->i_oparg = oparg; - ci->i_loc = loc; - - /* fix the labels map */ - for(int lbl=0; lbl < seq->s_labelmap_size; lbl++) { - if (seq->s_labelmap[lbl] >= pos) { - seq->s_labelmap[lbl]++; - } +static cfg_builder* +instr_sequence_to_cfg(instr_sequence *seq) { + if (_PyInstructionSequence_ApplyLabelMap(seq) < 0) { + return NULL; } - return SUCCESS; -} - -static void -instr_sequence_fini(instr_sequence *seq) { - PyObject_Free(seq->s_labelmap); - seq->s_labelmap = NULL; - - PyObject_Free(seq->s_instrs); - seq->s_instrs = NULL; -} - -static int -instr_sequence_to_cfg(instr_sequence *seq, cfg_builder *g) { - memset(g, 0, sizeof(cfg_builder)); - RETURN_IF_ERROR(_PyCfgBuilder_Init(g)); - - /* There can be more than one label for the same offset. The - * offset2lbl maping selects one of them which we use consistently. - */ - - int *offset2lbl = PyMem_Malloc(seq->s_used * sizeof(int)); - if (offset2lbl == NULL) { - PyErr_NoMemory(); - return ERROR; + cfg_builder *g = _PyCfgBuilder_New(); + if (g == NULL) { + return NULL; } for (int i = 0; i < seq->s_used; i++) { - offset2lbl[i] = -1; + seq->s_instrs[i].i_target = 0; } - for (int lbl=0; lbl < seq->s_labelmap_size; lbl++) { - int offset = seq->s_labelmap[lbl]; - if (offset >= 0) { - assert(offset < seq->s_used); - offset2lbl[offset] = lbl; + for (int i = 0; i < seq->s_used; i++) { + instruction *instr = &seq->s_instrs[i]; + if (HAS_TARGET(instr->i_opcode)) { + assert(instr->i_oparg >= 0 && instr->i_oparg < seq->s_used); + seq->s_instrs[instr->i_oparg].i_target = 1; } } - for (int i = 0; i < seq->s_used; i++) { - int lbl = offset2lbl[i]; - if (lbl >= 0) { - assert (lbl < seq->s_labelmap_size); - jump_target_label lbl_ = {lbl}; + instruction *instr = &seq->s_instrs[i]; + if (instr->i_target) { + jump_target_label lbl_ = {i}; if (_PyCfgBuilder_UseLabel(g, lbl_) < 0) { goto error; } } - instruction *instr = &seq->s_instrs[i]; int opcode = instr->i_opcode; int oparg = instr->i_oparg; - if (HAS_TARGET(opcode)) { - int offset = seq->s_labelmap[oparg]; - assert(offset >= 0 && offset < seq->s_used); - int lbl = offset2lbl[offset]; - assert(lbl >= 0 && lbl < seq->s_labelmap_size); - oparg = lbl; - } if (_PyCfgBuilder_Addop(g, opcode, oparg, instr->i_loc) < 0) { goto error; } } - PyMem_Free(offset2lbl); - - int nblocks = 0; - for (basicblock *b = g->g_block_list; b != NULL; b = b->b_list) { - nblocks++; - } - if ((size_t)nblocks > SIZE_MAX / sizeof(basicblock *)) { - PyErr_NoMemory(); - return ERROR; + if (_PyCfgBuilder_CheckSize(g) < 0) { + goto error; } - return SUCCESS; + return g; error: - PyMem_Free(offset2lbl); - return ERROR; + _PyCfgBuilder_Free(g); + return NULL; } - /* The following items change on entry and exit of code blocks. They must be saved and restored when returning to a block. */ @@ -385,9 +248,10 @@ struct compiler_unit { int u_scope_type; - PyObject *u_private; /* for private name mangling */ + PyObject *u_private; /* for private name mangling */ + PyObject *u_static_attributes; /* for class: attributes accessed via self.X */ - instr_sequence u_instr_sequence; /* codegen output */ + instr_sequence *u_instr_sequence; /* codegen output */ int u_nfblocks; int u_in_inlined_comp; @@ -412,7 +276,7 @@ handled by the symbol analysis pass. struct compiler { PyObject *c_filename; struct symtable *c_st; - PyFutureFeatures c_future; /* module's __future__ */ + _PyFutureFeatures c_future; /* module's __future__ */ PyCompilerFlags c_flags; int c_optimize; /* optimization level */ @@ -420,12 +284,17 @@ struct compiler { int c_nestlevel; PyObject *c_const_cache; /* Python dict holding all constants, including names tuple */ - struct compiler_unit *u; /* compiler state for current block */ + struct compiler_unit *u; /* compiler state for current block */ PyObject *c_stack; /* Python list holding compiler_unit ptrs */ PyArena *c_arena; /* pointer to memory allocation arena */ + + bool c_save_nested_seqs; /* if true, construct recursive instruction sequences + * (including instructions for nested code objects) + */ + int c_disable_warning; }; -#define INSTR_SEQUENCE(C) (&((C)->u->u_instr_sequence)) +#define INSTR_SEQUENCE(C) ((C)->u->u_instr_sequence) typedef struct { @@ -540,12 +409,9 @@ compiler_setup(struct compiler *c, mod_ty mod, PyObject *filename, c->c_flags = *flags; c->c_optimize = (optimize == -1) ? _Py_GetConfig()->optimization_level : optimize; c->c_nestlevel = 0; + c->c_save_nested_seqs = false; - _PyASTOptimizeState state; - state.optimize = c->c_optimize; - state.ff_features = merged; - - if (!_PyAST_Optimize(mod, arena, &state)) { + if (!_PyAST_Optimize(mod, arena, c->c_optimize, merged)) { return ERROR; } c->c_st = _PySymtable_Build(mod, filename, &c->c_future); @@ -589,6 +455,24 @@ _PyAST_Compile(mod_ty mod, PyObject *filename, PyCompilerFlags *pflags, return co; } +int +_PyCompile_AstOptimize(mod_ty mod, PyObject *filename, PyCompilerFlags *cf, + int optimize, PyArena *arena) +{ + _PyFutureFeatures future; + if (!_PyFuture_FromAST(mod, filename, &future)) { + return -1; + } + int flags = future.ff_features | cf->cf_flags; + if (optimize == -1) { + optimize = _Py_GetConfig()->optimization_level; + } + if (!_PyAST_Optimize(mod, arena, optimize, flags)) { + return -1; + } + return 0; +} + static void compiler_free(struct compiler *c) { @@ -692,7 +576,7 @@ dictbytype(PyObject *src, int scope_type, int flag, Py_ssize_t offset) static void compiler_unit_free(struct compiler_unit *u) { - instr_sequence_fini(&u->u_instr_sequence); + Py_CLEAR(u->u_instr_sequence); Py_CLEAR(u->u_ste); Py_CLEAR(u->u_metadata.u_name); Py_CLEAR(u->u_metadata.u_qualname); @@ -703,7 +587,34 @@ compiler_unit_free(struct compiler_unit *u) Py_CLEAR(u->u_metadata.u_cellvars); Py_CLEAR(u->u_metadata.u_fasthidden); Py_CLEAR(u->u_private); - PyObject_Free(u); + Py_CLEAR(u->u_static_attributes); + PyMem_Free(u); +} + +static int +compiler_maybe_add_static_attribute_to_class(struct compiler *c, expr_ty e) +{ + assert(e->kind == Attribute_kind); + expr_ty attr_value = e->v.Attribute.value; + if (attr_value->kind != Name_kind || + e->v.Attribute.ctx != Store || + !_PyUnicode_EqualToASCIIString(attr_value->v.Name.id, "self")) + { + return SUCCESS; + } + Py_ssize_t stack_size = PyList_GET_SIZE(c->c_stack); + for (Py_ssize_t i = stack_size - 1; i >= 0; i--) { + PyObject *capsule = PyList_GET_ITEM(c->c_stack, i); + struct compiler_unit *u = (struct compiler_unit *)PyCapsule_GetPointer( + capsule, CAPSULE_NAME); + assert(u); + if (u->u_scope_type == COMPILER_SCOPE_CLASS) { + assert(u->u_static_attributes); + RETURN_IF_ERROR(PySet_Add(u->u_static_attributes, e->v.Attribute.attr)); + break; + } + } + return SUCCESS; } static int @@ -808,35 +719,12 @@ stack_effect(int opcode, int oparg, int jump) // Specialized instructions are not supported. return PY_INVALID_STACK_EFFECT; } - int popped, pushed; - if (jump > 0) { - popped = _PyOpcode_num_popped(opcode, oparg, true); - pushed = _PyOpcode_num_pushed(opcode, oparg, true); - } - else { - popped = _PyOpcode_num_popped(opcode, oparg, false); - pushed = _PyOpcode_num_pushed(opcode, oparg, false); - } + int popped = _PyOpcode_num_popped(opcode, oparg); + int pushed = _PyOpcode_num_pushed(opcode, oparg); if (popped < 0 || pushed < 0) { return PY_INVALID_STACK_EFFECT; } - if (jump >= 0) { - return pushed - popped; - } - if (jump < 0) { - // Compute max(pushed - popped, alt_pushed - alt_popped) - int alt_popped = _PyOpcode_num_popped(opcode, oparg, true); - int alt_pushed = _PyOpcode_num_pushed(opcode, oparg, true); - if (alt_popped < 0 || alt_pushed < 0) { - return PY_INVALID_STACK_EFFECT; - } - int diff = pushed - popped; - int alt_diff = alt_pushed - alt_popped; - if (alt_diff > diff) { - return alt_diff; - } - return diff; - } + return pushed - popped; } // Pseudo ops @@ -846,6 +734,9 @@ stack_effect(int opcode, int oparg, int jump) case JUMP_NO_INTERRUPT: return 0; + case EXIT_INIT_CHECK: + return -1; + /* Exception handling pseudo-instructions */ case SETUP_FINALLY: /* 0 in the normal flow. @@ -864,6 +755,8 @@ stack_effect(int opcode, int oparg, int jump) case STORE_FAST_MAYBE_NULL: return -1; + case LOAD_CLOSURE: + return 1; case LOAD_METHOD: return 1; case LOAD_SUPER_METHOD: @@ -889,12 +782,60 @@ PyCompile_OpcodeStackEffect(int opcode, int oparg) return stack_effect(opcode, oparg, -1); } +int +_PyCompile_OpcodeIsValid(int opcode) +{ + return IS_VALID_OPCODE(opcode); +} + +int +_PyCompile_OpcodeHasArg(int opcode) +{ + return OPCODE_HAS_ARG(opcode); +} + +int +_PyCompile_OpcodeHasConst(int opcode) +{ + return OPCODE_HAS_CONST(opcode); +} + +int +_PyCompile_OpcodeHasName(int opcode) +{ + return OPCODE_HAS_NAME(opcode); +} + +int +_PyCompile_OpcodeHasJump(int opcode) +{ + return OPCODE_HAS_JUMP(opcode); +} + +int +_PyCompile_OpcodeHasFree(int opcode) +{ + return OPCODE_HAS_FREE(opcode); +} + +int +_PyCompile_OpcodeHasLocal(int opcode) +{ + return OPCODE_HAS_LOCAL(opcode); +} + +int +_PyCompile_OpcodeHasExc(int opcode) +{ + return IS_BLOCK_PUSH_OPCODE(opcode); +} + static int codegen_addop_noarg(instr_sequence *seq, int opcode, location loc) { - assert(!HAS_ARG(opcode)); + assert(!OPCODE_HAS_ARG(opcode)); assert(!IS_ASSEMBLER_OPCODE(opcode)); - return instr_sequence_addop(seq, opcode, 0, loc); + return _PyInstructionSequence_Addop(seq, opcode, 0, loc); } static Py_ssize_t @@ -903,11 +844,10 @@ dict_add_o(PyObject *dict, PyObject *o) PyObject *v; Py_ssize_t arg; - v = PyDict_GetItemWithError(dict, o); + if (PyDict_GetItemRef(dict, o, &v) < 0) { + return ERROR; + } if (!v) { - if (PyErr_Occurred()) { - return ERROR; - } arg = PyDict_GET_SIZE(dict); v = PyLong_FromSsize_t(arg); if (!v) { @@ -917,10 +857,10 @@ dict_add_o(PyObject *dict, PyObject *o) Py_DECREF(v); return ERROR; } - Py_DECREF(v); } else arg = PyLong_AsLong(v); + Py_DECREF(v); return arg; } @@ -929,10 +869,10 @@ static PyObject* merge_consts_recursive(PyObject *const_cache, PyObject *o) { assert(PyDict_CheckExact(const_cache)); - // None and Ellipsis are singleton, and key is the singleton. + // None and Ellipsis are immortal objects, and key is the singleton. // No need to merge object and key. if (o == Py_None || o == Py_Ellipsis) { - return Py_NewRef(o); + return o; } PyObject *key = _PyCode_ConstantKey(o); @@ -940,14 +880,15 @@ merge_consts_recursive(PyObject *const_cache, PyObject *o) return NULL; } - // t is borrowed reference - PyObject *t = PyDict_SetDefault(const_cache, key, key); - if (t != key) { - // o is registered in const_cache. Just use it. - Py_XINCREF(t); + PyObject *t; + int res = PyDict_SetDefaultRef(const_cache, key, key, &t); + if (res != 0) { + // o was not inserted into const_cache. t is either the existing value + // or NULL (on error). Py_DECREF(key); return t; } + Py_DECREF(t); // We registered o in const_cache. // When o is a tuple or frozenset, we want to merge its @@ -1053,7 +994,7 @@ compiler_addop_load_const(PyObject *const_cache, struct compiler_unit *u, locati if (arg < 0) { return ERROR; } - return codegen_addop_i(&u->u_instr_sequence, LOAD_CONST, arg, loc); + return codegen_addop_i(u->u_instr_sequence, LOAD_CONST, arg, loc); } static int @@ -1064,7 +1005,7 @@ compiler_addop_o(struct compiler_unit *u, location loc, if (arg < 0) { return ERROR; } - return codegen_addop_i(&u->u_instr_sequence, opcode, arg, loc); + return codegen_addop_i(u->u_instr_sequence, opcode, arg, loc); } static int @@ -1084,6 +1025,7 @@ compiler_addop_name(struct compiler_unit *u, location loc, arg <<= 1; } if (opcode == LOAD_METHOD) { + assert(is_pseudo_target(LOAD_METHOD, LOAD_ATTR)); opcode = LOAD_ATTR; arg <<= 1; arg |= 1; @@ -1093,20 +1035,23 @@ compiler_addop_name(struct compiler_unit *u, location loc, arg |= 2; } if (opcode == LOAD_SUPER_METHOD) { + assert(is_pseudo_target(LOAD_SUPER_METHOD, LOAD_SUPER_ATTR)); opcode = LOAD_SUPER_ATTR; arg <<= 2; arg |= 3; } if (opcode == LOAD_ZERO_SUPER_ATTR) { + assert(is_pseudo_target(LOAD_ZERO_SUPER_ATTR, LOAD_SUPER_ATTR)); opcode = LOAD_SUPER_ATTR; arg <<= 2; } if (opcode == LOAD_ZERO_SUPER_METHOD) { + assert(is_pseudo_target(LOAD_ZERO_SUPER_METHOD, LOAD_SUPER_ATTR)); opcode = LOAD_SUPER_ATTR; arg <<= 2; arg |= 1; } - return codegen_addop_i(&u->u_instr_sequence, opcode, arg, loc); + return codegen_addop_i(u->u_instr_sequence, opcode, arg, loc); } /* Add an opcode with an integer argument */ @@ -1123,7 +1068,7 @@ codegen_addop_i(instr_sequence *seq, int opcode, Py_ssize_t oparg, location loc) int oparg_ = Py_SAFE_DOWNCAST(oparg, Py_ssize_t, int); assert(!IS_ASSEMBLER_OPCODE(opcode)); - return instr_sequence_addop(seq, opcode, oparg_, loc); + return _PyInstructionSequence_Addop(seq, opcode, oparg_, loc); } static int @@ -1131,9 +1076,9 @@ codegen_addop_j(instr_sequence *seq, location loc, int opcode, jump_target_label target) { assert(IS_LABEL(target)); - assert(IS_JUMP_OPCODE(opcode) || IS_BLOCK_PUSH_OPCODE(opcode)); + assert(OPCODE_HAS_JUMP(opcode) || IS_BLOCK_PUSH_OPCODE(opcode)); assert(!IS_ASSEMBLER_OPCODE(opcode)); - return instr_sequence_addop(seq, opcode, target.id, loc); + return _PyInstructionSequence_Addop(seq, opcode, target.id, loc); } #define RETURN_IF_ERROR_IN_SCOPE(C, CALL) { \ @@ -1165,7 +1110,7 @@ codegen_addop_j(instr_sequence *seq, location loc, } #define ADDOP_N(C, LOC, OP, O, TYPE) { \ - assert(!HAS_CONST(OP)); /* use ADDOP_LOAD_CONST_NEW */ \ + assert(!OPCODE_HAS_CONST(OP)); /* use ADDOP_LOAD_CONST_NEW */ \ if (compiler_addop_o((C)->u, (LOC), (OP), (C)->u->u_metadata.u_ ## TYPE, (O)) < 0) { \ Py_DECREF((O)); \ return ERROR; \ @@ -1240,8 +1185,7 @@ compiler_enter_scope(struct compiler *c, identifier name, struct compiler_unit *u; - u = (struct compiler_unit *)PyObject_Calloc(1, sizeof( - struct compiler_unit)); + u = (struct compiler_unit *)PyMem_Calloc(1, sizeof(struct compiler_unit)); if (!u) { PyErr_NoMemory(); return ERROR; @@ -1250,7 +1194,7 @@ compiler_enter_scope(struct compiler *c, identifier name, u->u_metadata.u_argcount = 0; u->u_metadata.u_posonlyargcount = 0; u->u_metadata.u_kwonlyargcount = 0; - u->u_ste = PySymtable_Lookup(c->c_st, key); + u->u_ste = _PySymtable_Lookup(c->c_st, key); if (!u->u_ste) { compiler_unit_free(u); return ERROR; @@ -1315,6 +1259,18 @@ compiler_enter_scope(struct compiler *c, identifier name, } u->u_private = NULL; + if (scope_type == COMPILER_SCOPE_CLASS) { + u->u_static_attributes = PySet_New(0); + if (!u->u_static_attributes) { + compiler_unit_free(u); + return ERROR; + } + } + else { + u->u_static_attributes = NULL; + } + + u->u_instr_sequence = (instr_sequence*)_PyInstructionSequence_New(); /* Push the old compiler_unit on the stack. */ if (c->u) { @@ -1337,7 +1293,7 @@ compiler_enter_scope(struct compiler *c, identifier name, else { RETURN_IF_ERROR(compiler_set_qualname(c)); } - ADDOP_I(c, loc, RESUME, 0); + ADDOP_I(c, loc, RESUME, RESUME_AT_FUNC_START); if (u->u_scope_type == COMPILER_SCOPE_MODULE) { loc.lineno = -1; @@ -1351,6 +1307,11 @@ compiler_exit_scope(struct compiler *c) // Don't call PySequence_DelItem() with an exception raised PyObject *exc = PyErr_GetRaisedException(); + instr_sequence *nested_seq = NULL; + if (c->c_save_nested_seqs) { + nested_seq = c->u->u_instr_sequence; + Py_INCREF(nested_seq); + } c->c_nestlevel--; compiler_unit_free(c->u); /* Restore c->u to the parent unit. */ @@ -1361,13 +1322,20 @@ compiler_exit_scope(struct compiler *c) assert(c->u); /* we are deleting from a list so this really shouldn't fail */ if (PySequence_DelItem(c->c_stack, n) < 0) { - _PyErr_WriteUnraisableMsg("on removing the last compiler " - "stack item", NULL); + PyErr_FormatUnraisable("Exception ignored on removing " + "the last compiler stack item"); + } + if (nested_seq != NULL) { + if (_PyInstructionSequence_AddNested(c->u->u_instr_sequence, nested_seq) < 0) { + PyErr_FormatUnraisable("Exception ignored on appending " + "nested instruction sequence"); + } } } else { c->u = NULL; } + Py_XDECREF(nested_seq); PyErr_SetRaisedException(exc); } @@ -1470,6 +1438,9 @@ compiler_push_fblock(struct compiler *c, location loc, f->fb_loc = loc; f->fb_exit = exit; f->fb_datum = datum; + if (t == FINALLY_END) { + c->c_disable_warning++; + } return SUCCESS; } @@ -1481,6 +1452,9 @@ compiler_pop_fblock(struct compiler *c, enum fblocktype t, jump_target_label blo u->u_nfblocks--; assert(u->u_fblock[u->u_nfblocks].fb_type == t); assert(SAME_LABEL(u->u_fblock[u->u_nfblocks].fb_block, block_label)); + if (t == FINALLY_END) { + c->c_disable_warning--; + } } static int @@ -1505,9 +1479,9 @@ compiler_add_yield_from(struct compiler *c, location loc, int await) // Set up a virtual try/except to handle when StopIteration is raised during // a close or throw call. The only way YIELD_VALUE raises if they do! ADDOP_JUMP(c, loc, SETUP_FINALLY, fail); - ADDOP_I(c, loc, YIELD_VALUE, 0); + ADDOP_I(c, loc, YIELD_VALUE, 1); ADDOP(c, NO_LOCATION, POP_BLOCK); - ADDOP_I(c, loc, RESUME, await ? 3 : 2); + ADDOP_I(c, loc, RESUME, await ? RESUME_AFTER_AWAIT : RESUME_AFTER_YIELD_FROM); ADDOP_JUMP(c, loc, JUMP_NO_INTERRUPT, send); USE_LABEL(c, fail); @@ -1672,16 +1646,13 @@ compiler_unwind_fblock_stack(struct compiler *c, location *ploc, static int compiler_body(struct compiler *c, location loc, asdl_stmt_seq *stmts) { - int i = 0; - stmt_ty st; - PyObject *docstring; /* Set current line number to the line number of first statement. This way line number for SETUP_ANNOTATIONS will always coincide with the line number of first "real" statement in module. If body is empty, then lineno will be set later in optimize_and_assemble. */ if (c->u->u_scope_type == COMPILER_SCOPE_MODULE && asdl_seq_LEN(stmts)) { - st = (stmt_ty)asdl_seq_GET(stmts, 0); + stmt_ty st = (stmt_ty)asdl_seq_GET(stmts, 0); loc = LOC(st); } /* Every annotated class and module should have __annotations__. */ @@ -1691,18 +1662,25 @@ compiler_body(struct compiler *c, location loc, asdl_stmt_seq *stmts) if (!asdl_seq_LEN(stmts)) { return SUCCESS; } - /* if not -OO mode, set docstring */ - if (c->c_optimize < 2) { - docstring = _PyAST_GetDocString(stmts); - if (docstring) { - i = 1; - st = (stmt_ty)asdl_seq_GET(stmts, 0); + Py_ssize_t first_instr = 0; + PyObject *docstring = _PyAST_GetDocString(stmts); + if (docstring) { + first_instr = 1; + /* if not -OO mode, set docstring */ + if (c->c_optimize < 2) { + PyObject *cleandoc = _PyCompile_CleanDoc(docstring); + if (cleandoc == NULL) { + return ERROR; + } + stmt_ty st = (stmt_ty)asdl_seq_GET(stmts, 0); assert(st->kind == Expr_kind); - VISIT(c, expr, st->v.Expr.value); + location loc = LOC(st->v.Expr.value); + ADDOP_LOAD_CONST(c, loc, cleandoc); + Py_DECREF(cleandoc); RETURN_IF_ERROR(compiler_nameop(c, NO_LOCATION, &_Py_ID(__doc__), Store)); } } - for (; i < asdl_seq_LEN(stmts); i++) { + for (Py_ssize_t i = first_instr; i < asdl_seq_LEN(stmts); i++) { VISIT(c, stmt, (stmt_ty)asdl_seq_GET(stmts, i)); } return SUCCESS; @@ -1711,16 +1689,10 @@ compiler_body(struct compiler *c, location loc, asdl_stmt_seq *stmts) static int compiler_codegen(struct compiler *c, mod_ty mod) { - _Py_DECLARE_STR(anon_module, "<module>"); - RETURN_IF_ERROR( - compiler_enter_scope(c, &_Py_STR(anon_module), COMPILER_SCOPE_MODULE, - mod, 1)); - location loc = LOCATION(1, 1, 0, 0); switch (mod->kind) { case Module_kind: if (compiler_body(c, loc, mod->v.Module.body) < 0) { - compiler_exit_scope(c); return ERROR; } break; @@ -1729,10 +1701,10 @@ compiler_codegen(struct compiler *c, mod_ty mod) ADDOP(c, loc, SETUP_ANNOTATIONS); } c->c_interactive = 1; - VISIT_SEQ_IN_SCOPE(c, stmt, mod->v.Interactive.body); + VISIT_SEQ(c, stmt, mod->v.Interactive.body); break; case Expression_kind: - VISIT_IN_SCOPE(c, expr, mod->v.Expression.body); + VISIT(c, expr, mod->v.Expression.body); break; default: PyErr_Format(PyExc_SystemError, @@ -1743,14 +1715,29 @@ compiler_codegen(struct compiler *c, mod_ty mod) return SUCCESS; } +static int +compiler_enter_anonymous_scope(struct compiler* c, mod_ty mod) +{ + _Py_DECLARE_STR(anon_module, "<module>"); + RETURN_IF_ERROR( + compiler_enter_scope(c, &_Py_STR(anon_module), COMPILER_SCOPE_MODULE, + mod, 1)); + return SUCCESS; +} + static PyCodeObject * compiler_mod(struct compiler *c, mod_ty mod) { + PyCodeObject *co = NULL; int addNone = mod->kind != Expression_kind; - if (compiler_codegen(c, mod) < 0) { + if (compiler_enter_anonymous_scope(c, mod) < 0) { return NULL; } - PyCodeObject *co = optimize_and_assemble(c, addNone); + if (compiler_codegen(c, mod) < 0) { + goto finally; + } + co = optimize_and_assemble(c, addNone); +finally: compiler_exit_scope(c); return co; } @@ -1798,7 +1785,7 @@ compiler_make_closure(struct compiler *c, location loc, PyCodeObject *co, Py_ssize_t flags) { if (co->co_nfreevars) { - int i = PyCode_GetFirstFree(co); + int i = PyUnstable_Code_GetFirstFree(co); for (; i < co->co_nlocalsplus; ++i) { /* Bypass com_addop_varname because it will generate LOAD_DEREF but LOAD_CLOSURE is needed. @@ -1840,11 +1827,25 @@ compiler_make_closure(struct compiler *c, location loc, } ADDOP_I(c, loc, LOAD_CLOSURE, arg); } - flags |= 0x08; + flags |= MAKE_FUNCTION_CLOSURE; ADDOP_I(c, loc, BUILD_TUPLE, co->co_nfreevars); } ADDOP_LOAD_CONST(c, loc, (PyObject*)co); - ADDOP_I(c, loc, MAKE_FUNCTION, flags); + + ADDOP(c, loc, MAKE_FUNCTION); + + if (flags & MAKE_FUNCTION_CLOSURE) { + ADDOP_I(c, loc, SET_FUNCTION_ATTRIBUTE, MAKE_FUNCTION_CLOSURE); + } + if (flags & MAKE_FUNCTION_ANNOTATIONS) { + ADDOP_I(c, loc, SET_FUNCTION_ATTRIBUTE, MAKE_FUNCTION_ANNOTATIONS); + } + if (flags & MAKE_FUNCTION_KWDEFAULTS) { + ADDOP_I(c, loc, SET_FUNCTION_ATTRIBUTE, MAKE_FUNCTION_KWDEFAULTS); + } + if (flags & MAKE_FUNCTION_DEFAULTS) { + ADDOP_I(c, loc, SET_FUNCTION_ATTRIBUTE, MAKE_FUNCTION_DEFAULTS); + } return SUCCESS; } @@ -2051,7 +2052,7 @@ compiler_default_arguments(struct compiler *c, location loc, Py_ssize_t funcflags = 0; if (args->defaults && asdl_seq_LEN(args->defaults) > 0) { RETURN_IF_ERROR(compiler_visit_defaults(c, args, loc)); - funcflags |= 0x01; + funcflags |= MAKE_FUNCTION_DEFAULTS; } if (args->kwonlyargs) { int res = compiler_visit_kwonlydefaults(c, loc, @@ -2059,7 +2060,7 @@ compiler_default_arguments(struct compiler *c, location loc, args->kw_defaults); RETURN_IF_ERROR(res); if (res > 0) { - funcflags |= 0x02; + funcflags |= MAKE_FUNCTION_KWDEFAULTS; } } return funcflags; @@ -2121,7 +2122,7 @@ wrap_in_stopiteration_handler(struct compiler *c) /* Insert SETUP_CLEANUP at start */ RETURN_IF_ERROR( - instr_sequence_insert_instruction( + _PyInstructionSequence_InsertInstruction( INSTR_SEQUENCE(c), 0, SETUP_CLEANUP, handler.id, NO_LOCATION)); @@ -2134,12 +2135,43 @@ wrap_in_stopiteration_handler(struct compiler *c) } static int +compiler_type_param_bound_or_default(struct compiler *c, expr_ty e, + identifier name, void *key, + bool allow_starred) +{ + if (compiler_enter_scope(c, name, COMPILER_SCOPE_TYPEPARAMS, + key, e->lineno) == -1) { + return ERROR; + } + if (allow_starred && e->kind == Starred_kind) { + VISIT(c, expr, e->v.Starred.value); + ADDOP_I(c, LOC(e), UNPACK_SEQUENCE, (Py_ssize_t)1); + } + else { + VISIT(c, expr, e); + } + ADDOP_IN_SCOPE(c, LOC(e), RETURN_VALUE); + PyCodeObject *co = optimize_and_assemble(c, 1); + compiler_exit_scope(c); + if (co == NULL) { + return ERROR; + } + if (compiler_make_closure(c, LOC(e), co, 0) < 0) { + Py_DECREF(co); + return ERROR; + } + Py_DECREF(co); + return SUCCESS; +} + +static int compiler_type_params(struct compiler *c, asdl_type_param_seq *type_params) { if (!type_params) { return SUCCESS; } Py_ssize_t n = asdl_seq_LEN(type_params); + bool seen_default = false; for (Py_ssize_t i = 0; i < n; i++) { type_param_ty typeparam = asdl_seq_GET(type_params, i); @@ -2149,22 +2181,10 @@ compiler_type_params(struct compiler *c, asdl_type_param_seq *type_params) ADDOP_LOAD_CONST(c, loc, typeparam->v.TypeVar.name); if (typeparam->v.TypeVar.bound) { expr_ty bound = typeparam->v.TypeVar.bound; - if (compiler_enter_scope(c, typeparam->v.TypeVar.name, COMPILER_SCOPE_TYPEPARAMS, - (void *)typeparam, bound->lineno) == -1) { - return ERROR; - } - VISIT_IN_SCOPE(c, expr, bound); - ADDOP_IN_SCOPE(c, loc, RETURN_VALUE); - PyCodeObject *co = optimize_and_assemble(c, 1); - compiler_exit_scope(c); - if (co == NULL) { - return ERROR; - } - if (compiler_make_closure(c, loc, co, 0) < 0) { - Py_DECREF(co); + if (compiler_type_param_bound_or_default(c, bound, typeparam->v.TypeVar.name, + (void *)typeparam, false) < 0) { return ERROR; } - Py_DECREF(co); int intrinsic = bound->kind == Tuple_kind ? INTRINSIC_TYPEVAR_WITH_CONSTRAINTS @@ -2174,18 +2194,60 @@ compiler_type_params(struct compiler *c, asdl_type_param_seq *type_params) else { ADDOP_I(c, loc, CALL_INTRINSIC_1, INTRINSIC_TYPEVAR); } + if (typeparam->v.TypeVar.default_value) { + seen_default = true; + expr_ty default_ = typeparam->v.TypeVar.default_value; + if (compiler_type_param_bound_or_default(c, default_, typeparam->v.TypeVar.name, + (void *)((uintptr_t)typeparam + 1), false) < 0) { + return ERROR; + } + ADDOP_I(c, loc, CALL_INTRINSIC_2, INTRINSIC_SET_TYPEPARAM_DEFAULT); + } + else if (seen_default) { + return compiler_error(c, loc, "non-default type parameter '%U' " + "follows default type parameter", + typeparam->v.TypeVar.name); + } ADDOP_I(c, loc, COPY, 1); RETURN_IF_ERROR(compiler_nameop(c, loc, typeparam->v.TypeVar.name, Store)); break; case TypeVarTuple_kind: ADDOP_LOAD_CONST(c, loc, typeparam->v.TypeVarTuple.name); ADDOP_I(c, loc, CALL_INTRINSIC_1, INTRINSIC_TYPEVARTUPLE); + if (typeparam->v.TypeVarTuple.default_value) { + expr_ty default_ = typeparam->v.TypeVarTuple.default_value; + if (compiler_type_param_bound_or_default(c, default_, typeparam->v.TypeVarTuple.name, + (void *)typeparam, true) < 0) { + return ERROR; + } + ADDOP_I(c, loc, CALL_INTRINSIC_2, INTRINSIC_SET_TYPEPARAM_DEFAULT); + seen_default = true; + } + else if (seen_default) { + return compiler_error(c, loc, "non-default type parameter '%U' " + "follows default type parameter", + typeparam->v.TypeVarTuple.name); + } ADDOP_I(c, loc, COPY, 1); RETURN_IF_ERROR(compiler_nameop(c, loc, typeparam->v.TypeVarTuple.name, Store)); break; case ParamSpec_kind: ADDOP_LOAD_CONST(c, loc, typeparam->v.ParamSpec.name); ADDOP_I(c, loc, CALL_INTRINSIC_1, INTRINSIC_PARAMSPEC); + if (typeparam->v.ParamSpec.default_value) { + expr_ty default_ = typeparam->v.ParamSpec.default_value; + if (compiler_type_param_bound_or_default(c, default_, typeparam->v.ParamSpec.name, + (void *)typeparam, false) < 0) { + return ERROR; + } + ADDOP_I(c, loc, CALL_INTRINSIC_2, INTRINSIC_SET_TYPEPARAM_DEFAULT); + seen_default = true; + } + else if (seen_default) { + return compiler_error(c, loc, "non-default type parameter '%U' " + "follows default type parameter", + typeparam->v.ParamSpec.name); + } ADDOP_I(c, loc, COPY, 1); RETURN_IF_ERROR(compiler_nameop(c, loc, typeparam->v.ParamSpec.name, Store)); break; @@ -2199,7 +2261,6 @@ static int compiler_function_body(struct compiler *c, stmt_ty s, int is_async, Py_ssize_t funcflags, int firstlineno) { - PyObject *docstring = NULL; arguments_ty args; identifier name; asdl_stmt_seq *body; @@ -2226,14 +2287,28 @@ compiler_function_body(struct compiler *c, stmt_ty s, int is_async, Py_ssize_t f RETURN_IF_ERROR( compiler_enter_scope(c, name, scope_type, (void *)s, firstlineno)); - /* if not -OO mode, add docstring */ - if (c->c_optimize < 2) { - docstring = _PyAST_GetDocString(body); + Py_ssize_t first_instr = 0; + PyObject *docstring = _PyAST_GetDocString(body); + if (docstring) { + first_instr = 1; + /* if not -OO mode, add docstring */ + if (c->c_optimize < 2) { + docstring = _PyCompile_CleanDoc(docstring); + if (docstring == NULL) { + compiler_exit_scope(c); + return ERROR; + } + } + else { + docstring = NULL; + } } if (compiler_add_const(c->c_const_cache, c->u, docstring ? docstring : Py_None) < 0) { + Py_XDECREF(docstring); compiler_exit_scope(c); return ERROR; } + Py_CLEAR(docstring); c->u->u_metadata.u_argcount = asdl_seq_LEN(args->args); c->u->u_metadata.u_posonlyargcount = asdl_seq_LEN(args->posonlyargs); @@ -2249,7 +2324,7 @@ compiler_function_body(struct compiler *c, stmt_ty s, int is_async, Py_ssize_t f start, NO_LABEL, NULL)); } - for (Py_ssize_t i = docstring ? 1 : 0; i < asdl_seq_LEN(body); i++) { + for (Py_ssize_t i = first_instr; i < asdl_seq_LEN(body); i++) { VISIT_IN_SCOPE(c, stmt, (stmt_ty)asdl_seq_GET(body, i)); } if (add_stopiteration_handler) { @@ -2316,11 +2391,6 @@ compiler_function(struct compiler *c, stmt_ty s, int is_async) int is_generic = asdl_seq_LEN(type_params) > 0; - if (is_generic) { - // Used by the CALL to the type parameters function. - ADDOP(c, loc, PUSH_NULL); - } - funcflags = compiler_default_arguments(c, loc, args); if (funcflags == -1) { return ERROR; @@ -2329,10 +2399,10 @@ compiler_function(struct compiler *c, stmt_ty s, int is_async) int num_typeparam_args = 0; if (is_generic) { - if (funcflags & 0x01) { + if (funcflags & MAKE_FUNCTION_DEFAULTS) { num_typeparam_args += 1; } - if (funcflags & 0x02) { + if (funcflags & MAKE_FUNCTION_KWDEFAULTS) { num_typeparam_args += 1; } if (num_typeparam_args == 2) { @@ -2349,11 +2419,8 @@ compiler_function(struct compiler *c, stmt_ty s, int is_async) } Py_DECREF(type_params_name); RETURN_IF_ERROR_IN_SCOPE(c, compiler_type_params(c, type_params)); - if ((funcflags & 0x01) || (funcflags & 0x02)) { - RETURN_IF_ERROR_IN_SCOPE(c, codegen_addop_i(INSTR_SEQUENCE(c), LOAD_FAST, 0, loc)); - } - if ((funcflags & 0x01) && (funcflags & 0x02)) { - RETURN_IF_ERROR_IN_SCOPE(c, codegen_addop_i(INSTR_SEQUENCE(c), LOAD_FAST, 1, loc)); + for (int i = 0; i < num_typeparam_args; i++) { + RETURN_IF_ERROR_IN_SCOPE(c, codegen_addop_i(INSTR_SEQUENCE(c), LOAD_FAST, i, loc)); } } @@ -2365,7 +2432,7 @@ compiler_function(struct compiler *c, stmt_ty s, int is_async) return ERROR; } if (annotations > 0) { - funcflags |= 0x04; + funcflags |= MAKE_FUNCTION_ANNOTATIONS; } if (compiler_function_body(c, s, is_async, funcflags, firstlineno) < 0) { @@ -2394,8 +2461,12 @@ compiler_function(struct compiler *c, stmt_ty s, int is_async) Py_DECREF(co); if (num_typeparam_args > 0) { ADDOP_I(c, loc, SWAP, num_typeparam_args + 1); + ADDOP_I(c, loc, CALL, num_typeparam_args - 1); + } + else { + ADDOP(c, loc, PUSH_NULL); + ADDOP_I(c, loc, CALL, 0); } - ADDOP_I(c, loc, CALL, num_typeparam_args); } RETURN_IF_ERROR(compiler_apply_decorators(c, decos)); @@ -2449,6 +2520,11 @@ compiler_class_body(struct compiler *c, stmt_ty s, int firstlineno) compiler_exit_scope(c); return ERROR; } + ADDOP_LOAD_CONST_NEW(c, loc, PyLong_FromLong(c->u->u_metadata.u_firstlineno)); + if (compiler_nameop(c, loc, &_Py_ID(__firstlineno__), Store) < 0) { + compiler_exit_scope(c); + return ERROR; + } asdl_type_param_seq *type_params = s->v.ClassDef.type_params; if (asdl_seq_LEN(type_params) > 0) { if (!compiler_set_type_params_in_class(c, loc)) { @@ -2474,6 +2550,29 @@ compiler_class_body(struct compiler *c, stmt_ty s, int firstlineno) compiler_exit_scope(c); return ERROR; } + assert(c->u->u_static_attributes); + PyObject *static_attributes_unsorted = PySequence_List(c->u->u_static_attributes); + if (static_attributes_unsorted == NULL) { + compiler_exit_scope(c); + return ERROR; + } + if (PyList_Sort(static_attributes_unsorted) != 0) { + compiler_exit_scope(c); + Py_DECREF(static_attributes_unsorted); + return ERROR; + } + PyObject *static_attributes = PySequence_Tuple(static_attributes_unsorted); + Py_DECREF(static_attributes_unsorted); + if (static_attributes == NULL) { + compiler_exit_scope(c); + return ERROR; + } + ADDOP_LOAD_CONST(c, NO_LOCATION, static_attributes); + Py_CLEAR(static_attributes); + if (compiler_nameop(c, NO_LOCATION, &_Py_ID(__static_attributes__), Store) < 0) { + compiler_exit_scope(c); + return ERROR; + } /* The following code is artificial */ /* Set __classdictcell__ if necessary */ if (c->u->u_ste->ste_needs_classdict) { @@ -2523,8 +2622,8 @@ compiler_class_body(struct compiler *c, stmt_ty s, int firstlineno) // these instructions should be attributed to the class line, // not a decorator line loc = LOC(s); - ADDOP(c, loc, PUSH_NULL); ADDOP(c, loc, LOAD_BUILD_CLASS); + ADDOP(c, loc, PUSH_NULL); /* 3. load a function (or closure) made from the code object */ if (compiler_make_closure(c, loc, co, 0) < 0) { @@ -2555,7 +2654,6 @@ compiler_class(struct compiler *c, stmt_ty s) asdl_type_param_seq *type_params = s->v.ClassDef.type_params; int is_generic = asdl_seq_LEN(type_params) > 0; if (is_generic) { - ADDOP(c, loc, PUSH_NULL); PyObject *type_params_name = PyUnicode_FromFormat("<generic parameters of %U>", s->v.ClassDef.name); if (!type_params_name) { @@ -2615,6 +2713,7 @@ compiler_class(struct compiler *c, stmt_ty s) s->v.ClassDef.keywords)); PyCodeObject *co = optimize_and_assemble(c, 0); + compiler_exit_scope(c); if (co == NULL) { return ERROR; @@ -2624,6 +2723,7 @@ compiler_class(struct compiler *c, stmt_ty s) return ERROR; } Py_DECREF(co); + ADDOP(c, loc, PUSH_NULL); ADDOP_I(c, loc, CALL, 0); } else { RETURN_IF_ERROR(compiler_call_helper(c, loc, 2, @@ -2674,7 +2774,6 @@ compiler_typealias(struct compiler *c, stmt_ty s) int is_generic = asdl_seq_LEN(type_params) > 0; PyObject *name = s->v.TypeAlias.name->v.Name.id; if (is_generic) { - ADDOP(c, loc, PUSH_NULL); PyObject *type_params_name = PyUnicode_FromFormat("<generic parameters of %U>", name); if (!type_params_name) { @@ -2714,6 +2813,7 @@ compiler_typealias(struct compiler *c, stmt_ty s) return ERROR; } Py_DECREF(co); + ADDOP(c, loc, PUSH_NULL); ADDOP_I(c, loc, CALL, 0); } RETURN_IF_ERROR(compiler_nameop(c, loc, name, Store)); @@ -2815,9 +2915,11 @@ static int compiler_addcompare(struct compiler *c, location loc, default: Py_UNREACHABLE(); } - /* cmp goes in top bits of the oparg, while the low bits are used by quickened - * versions of this opcode to store the comparison mask. */ - ADDOP_I(c, loc, COMPARE_OP, (cmp << 4) | compare_masks[cmp]); + // cmp goes in top three bits of the oparg, while the low four bits are used + // by quickened versions of this opcode to store the comparison mask. The + // fifth-lowest bit indicates whether the result should be converted to bool + // and is set later): + ADDOP_I(c, loc, COMPARE_OP, (cmp << 5) | compare_masks[cmp]); return SUCCESS; } @@ -2862,7 +2964,7 @@ compiler_jump_if(struct compiler *c, location loc, compiler_jump_if(c, loc, e->v.IfExp.test, next2, 0)); RETURN_IF_ERROR( compiler_jump_if(c, loc, e->v.IfExp.body, next, cond)); - ADDOP_JUMP(c, NO_LOCATION, JUMP, end); + ADDOP_JUMP(c, NO_LOCATION, JUMP_NO_INTERRUPT, end); USE_LABEL(c, next2); RETURN_IF_ERROR( @@ -2883,18 +2985,20 @@ compiler_jump_if(struct compiler *c, location loc, ADDOP_I(c, LOC(e), SWAP, 2); ADDOP_I(c, LOC(e), COPY, 2); ADDOP_COMPARE(c, LOC(e), asdl_seq_GET(e->v.Compare.ops, i)); + ADDOP(c, LOC(e), TO_BOOL); ADDOP_JUMP(c, LOC(e), POP_JUMP_IF_FALSE, cleanup); } VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Compare.comparators, n)); ADDOP_COMPARE(c, LOC(e), asdl_seq_GET(e->v.Compare.ops, n)); + ADDOP(c, LOC(e), TO_BOOL); ADDOP_JUMP(c, LOC(e), cond ? POP_JUMP_IF_TRUE : POP_JUMP_IF_FALSE, next); NEW_JUMP_TARGET_LABEL(c, end); - ADDOP_JUMP(c, NO_LOCATION, JUMP, end); + ADDOP_JUMP(c, NO_LOCATION, JUMP_NO_INTERRUPT, end); USE_LABEL(c, cleanup); ADDOP(c, LOC(e), POP_TOP); if (!cond) { - ADDOP_JUMP(c, NO_LOCATION, JUMP, next); + ADDOP_JUMP(c, NO_LOCATION, JUMP_NO_INTERRUPT, next); } USE_LABEL(c, end); @@ -2910,6 +3014,7 @@ compiler_jump_if(struct compiler *c, location loc, /* general implementation */ VISIT(c, expr, e); + ADDOP(c, LOC(e), TO_BOOL); ADDOP_JUMP(c, LOC(e), cond ? POP_JUMP_IF_TRUE : POP_JUMP_IF_FALSE, next); return SUCCESS; } @@ -2925,7 +3030,7 @@ compiler_ifexp(struct compiler *c, expr_ty e) compiler_jump_if(c, LOC(e), e->v.IfExp.test, next, 0)); VISIT(c, expr, e->v.IfExp.body); - ADDOP_JUMP(c, NO_LOCATION, JUMP, end); + ADDOP_JUMP(c, NO_LOCATION, JUMP_NO_INTERRUPT, end); USE_LABEL(c, next); VISIT(c, expr, e->v.IfExp.orelse); @@ -3003,7 +3108,7 @@ compiler_if(struct compiler *c, stmt_ty s) VISIT_SEQ(c, stmt, s->v.If.body); if (asdl_seq_LEN(s->v.If.orelse)) { - ADDOP_JUMP(c, NO_LOCATION, JUMP, end); + ADDOP_JUMP(c, NO_LOCATION, JUMP_NO_INTERRUPT, end); USE_LABEL(c, next); VISIT_SEQ(c, stmt, s->v.If.orelse); @@ -3044,7 +3149,12 @@ compiler_for(struct compiler *c, stmt_ty s) ADDOP_JUMP(c, NO_LOCATION, JUMP, start); USE_LABEL(c, cleanup); + /* It is important for instrumentation that the `END_FOR` comes first. + * Iteration over a generator will jump to the first of these instructions, + * but a non-generator will jump to a later instruction. + */ ADDOP(c, NO_LOCATION, END_FOR); + ADDOP(c, NO_LOCATION, POP_TOP); compiler_pop_fblock(c, FOR_LOOP, start); @@ -3263,7 +3373,7 @@ compiler_try_finally(struct compiler *c, stmt_ty s) compiler_pop_fblock(c, FINALLY_TRY, body); VISIT_SEQ(c, stmt, s->v.Try.finalbody); - ADDOP_JUMP(c, NO_LOCATION, JUMP, exit); + ADDOP_JUMP(c, NO_LOCATION, JUMP_NO_INTERRUPT, exit); /* `finally` block */ USE_LABEL(c, end); @@ -3313,7 +3423,7 @@ compiler_try_star_finally(struct compiler *c, stmt_ty s) compiler_pop_fblock(c, FINALLY_TRY, body); VISIT_SEQ(c, stmt, s->v.TryStar.finalbody); - ADDOP_JUMP(c, NO_LOCATION, JUMP, exit); + ADDOP_JUMP(c, NO_LOCATION, JUMP_NO_INTERRUPT, exit); /* `finally` block */ USE_LABEL(c, end); @@ -3388,7 +3498,7 @@ compiler_try_except(struct compiler *c, stmt_ty s) if (s->v.Try.orelse && asdl_seq_LEN(s->v.Try.orelse)) { VISIT_SEQ(c, stmt, s->v.Try.orelse); } - ADDOP_JUMP(c, NO_LOCATION, JUMP, end); + ADDOP_JUMP(c, NO_LOCATION, JUMP_NO_INTERRUPT, end); n = asdl_seq_LEN(s->v.Try.handlers); USE_LABEL(c, except); @@ -3452,7 +3562,7 @@ compiler_try_except(struct compiler *c, stmt_ty s) compiler_nameop(c, NO_LOCATION, handler->v.ExceptHandler.name, Store)); RETURN_IF_ERROR( compiler_nameop(c, NO_LOCATION, handler->v.ExceptHandler.name, Del)); - ADDOP_JUMP(c, NO_LOCATION, JUMP, end); + ADDOP_JUMP(c, NO_LOCATION, JUMP_NO_INTERRUPT, end); /* except: */ USE_LABEL(c, cleanup_end); @@ -3480,7 +3590,7 @@ compiler_try_except(struct compiler *c, stmt_ty s) compiler_pop_fblock(c, HANDLER_CLEANUP, cleanup_body); ADDOP(c, NO_LOCATION, POP_BLOCK); ADDOP(c, NO_LOCATION, POP_EXCEPT); - ADDOP_JUMP(c, NO_LOCATION, JUMP, end); + ADDOP_JUMP(c, NO_LOCATION, JUMP_NO_INTERRUPT, end); } USE_LABEL(c, except); @@ -3568,7 +3678,7 @@ compiler_try_star_except(struct compiler *c, stmt_ty s) VISIT_SEQ(c, stmt, s->v.TryStar.body); compiler_pop_fblock(c, TRY_EXCEPT, body); ADDOP(c, NO_LOCATION, POP_BLOCK); - ADDOP_JUMP(c, NO_LOCATION, JUMP, orelse); + ADDOP_JUMP(c, NO_LOCATION, JUMP_NO_INTERRUPT, orelse); Py_ssize_t n = asdl_seq_LEN(s->v.TryStar.handlers); USE_LABEL(c, except); @@ -3650,7 +3760,7 @@ compiler_try_star_except(struct compiler *c, stmt_ty s) RETURN_IF_ERROR( compiler_nameop(c, NO_LOCATION, handler->v.ExceptHandler.name, Del)); } - ADDOP_JUMP(c, NO_LOCATION, JUMP, except); + ADDOP_JUMP(c, NO_LOCATION, JUMP_NO_INTERRUPT, except); /* except: */ USE_LABEL(c, cleanup_end); @@ -3667,11 +3777,11 @@ compiler_try_star_except(struct compiler *c, stmt_ty s) /* add exception raised to the res list */ ADDOP_I(c, NO_LOCATION, LIST_APPEND, 3); // exc ADDOP(c, NO_LOCATION, POP_TOP); // lasti - ADDOP_JUMP(c, NO_LOCATION, JUMP, except_with_error); + ADDOP_JUMP(c, NO_LOCATION, JUMP_NO_INTERRUPT, except_with_error); USE_LABEL(c, except); ADDOP(c, NO_LOCATION, NOP); // to hold a propagated location info - ADDOP_JUMP(c, NO_LOCATION, JUMP, except_with_error); + ADDOP_JUMP(c, NO_LOCATION, JUMP_NO_INTERRUPT, except_with_error); USE_LABEL(c, no_match); ADDOP(c, loc, POP_TOP); // match (None) @@ -3681,7 +3791,7 @@ compiler_try_star_except(struct compiler *c, stmt_ty s) if (i == n - 1) { /* Add exc to the list (if not None it's the unhandled part of the EG) */ ADDOP_I(c, NO_LOCATION, LIST_APPEND, 1); - ADDOP_JUMP(c, NO_LOCATION, JUMP, reraise_star); + ADDOP_JUMP(c, NO_LOCATION, JUMP_NO_INTERRUPT, reraise_star); } } /* artificial */ @@ -3697,7 +3807,7 @@ compiler_try_star_except(struct compiler *c, stmt_ty s) ADDOP(c, NO_LOCATION, POP_TOP); ADDOP(c, NO_LOCATION, POP_BLOCK); ADDOP(c, NO_LOCATION, POP_EXCEPT); - ADDOP_JUMP(c, NO_LOCATION, JUMP, end); + ADDOP_JUMP(c, NO_LOCATION, JUMP_NO_INTERRUPT, end); USE_LABEL(c, reraise); ADDOP(c, NO_LOCATION, POP_BLOCK); @@ -3841,7 +3951,7 @@ compiler_from_import(struct compiler *c, stmt_ty s) } if (location_is_after(LOC(s), c->c_future.ff_location) && - s->v.ImportFrom.module && + s->v.ImportFrom.module && s->v.ImportFrom.level == 0 && _PyUnicode_EqualToASCIIString(s->v.ImportFrom.module, "__future__")) { Py_DECREF(names); @@ -4036,8 +4146,6 @@ unaryop(unaryop_ty op) switch (op) { case Invert: return UNARY_INVERT; - case Not: - return UNARY_NOT; case USub: return UNARY_NEGATIVE; default: @@ -4108,7 +4216,7 @@ addop_yield(struct compiler *c, location loc) { ADDOP_I(c, loc, CALL_INTRINSIC_1, INTRINSIC_ASYNC_GEN_WRAP); } ADDOP_I(c, loc, YIELD_VALUE, 0); - ADDOP_I(c, loc, RESUME, 1); + ADDOP_I(c, loc, RESUME, RESUME_AFTER_YIELD); return SUCCESS; } @@ -4149,9 +4257,20 @@ compiler_nameop(struct compiler *c, location loc, optype = OP_DEREF; break; case LOCAL: - if (_PyST_IsFunctionLike(c->u->u_ste) || - (PyDict_GetItem(c->u->u_metadata.u_fasthidden, mangled) == Py_True)) + if (_PyST_IsFunctionLike(c->u->u_ste)) { optype = OP_FAST; + } + else { + PyObject *item; + if (PyDict_GetItemRef(c->u->u_metadata.u_fasthidden, mangled, + &item) < 0) { + goto error; + } + if (item == Py_True) { + optype = OP_FAST; + } + Py_XDECREF(item); + } break; case GLOBAL_IMPLICIT: if (_PyST_IsFunctionLike(c->u->u_ste)) @@ -4176,7 +4295,7 @@ compiler_nameop(struct compiler *c, location loc, op = LOAD_FROM_DICT_OR_DEREF; // First load the locals if (codegen_addop_noarg(INSTR_SEQUENCE(c), LOAD_LOCALS, loc) < 0) { - return ERROR; + goto error; } } else if (c->u->u_ste->ste_can_see_class_scope) { @@ -4184,7 +4303,7 @@ compiler_nameop(struct compiler *c, location loc, // First load the classdict if (compiler_addop_o(c->u, loc, LOAD_DEREF, c->u->u_metadata.u_freevars, &_Py_ID(__classdict__)) < 0) { - return ERROR; + goto error; } } else { @@ -4211,7 +4330,7 @@ compiler_nameop(struct compiler *c, location loc, // First load the classdict if (compiler_addop_o(c->u, loc, LOAD_DEREF, c->u->u_metadata.u_freevars, &_Py_ID(__classdict__)) < 0) { - return ERROR; + goto error; } } else { op = LOAD_GLOBAL; @@ -4245,6 +4364,10 @@ compiler_nameop(struct compiler *c, location loc, arg <<= 1; } return codegen_addop_i(INSTR_SEQUENCE(c), op, arg, loc); + +error: + Py_DECREF(mangled); + return ERROR; } static int @@ -4267,6 +4390,7 @@ compiler_boolop(struct compiler *c, expr_ty e) for (i = 0; i < n; ++i) { VISIT(c, expr, (expr_ty)asdl_seq_GET(s, i)); ADDOP_I(c, loc, COPY, 1); + ADDOP(c, loc, TO_BOOL); ADDOP_JUMP(c, loc, jumpi, end); ADDOP(c, loc, POP_TOP); } @@ -4574,13 +4698,14 @@ compiler_compare(struct compiler *c, expr_ty e) ADDOP_I(c, loc, COPY, 2); ADDOP_COMPARE(c, loc, asdl_seq_GET(e->v.Compare.ops, i)); ADDOP_I(c, loc, COPY, 1); + ADDOP(c, loc, TO_BOOL); ADDOP_JUMP(c, loc, POP_JUMP_IF_FALSE, cleanup); ADDOP(c, loc, POP_TOP); } VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Compare.comparators, n)); ADDOP_COMPARE(c, loc, asdl_seq_GET(e->v.Compare.ops, n)); NEW_JUMP_TARGET_LABEL(c, end); - ADDOP_JUMP(c, NO_LOCATION, JUMP, end); + ADDOP_JUMP(c, NO_LOCATION, JUMP_NO_INTERRUPT, end); USE_LABEL(c, cleanup); ADDOP_I(c, loc, SWAP, 2); @@ -4900,9 +5025,13 @@ maybe_optimize_method_call(struct compiler *c, expr_ty e) VISIT_SEQ(c, keyword, kwds); RETURN_IF_ERROR( compiler_call_simple_kw_helper(c, loc, kwds, kwdsl)); + loc = update_start_location_to_match_attr(c, LOC(e), meth); + ADDOP_I(c, loc, CALL_KW, argsl + kwdsl); + } + else { + loc = update_start_location_to_match_attr(c, LOC(e), meth); + ADDOP_I(c, loc, CALL, argsl); } - loc = update_start_location_to_match_attr(c, LOC(e), meth); - ADDOP_I(c, loc, CALL, argsl + kwdsl); return 1; } @@ -4942,9 +5071,9 @@ compiler_call(struct compiler *c, expr_ty e) return SUCCESS; } RETURN_IF_ERROR(check_caller(c, e->v.Call.func)); + VISIT(c, expr, e->v.Call.func); location loc = LOC(e->v.Call.func); ADDOP(c, loc, PUSH_NULL); - VISIT(c, expr, e->v.Call.func); loc = LOC(e); return compiler_call_helper(c, loc, 0, e->v.Call.args, @@ -4969,8 +5098,12 @@ compiler_joined_str(struct compiler *c, expr_ty e) } else { VISIT_SEQ(c, expr, e->v.JoinedStr.values); - if (asdl_seq_LEN(e->v.JoinedStr.values) != 1) { - ADDOP_I(c, loc, BUILD_STRING, asdl_seq_LEN(e->v.JoinedStr.values)); + if (value_count > 1) { + ADDOP_I(c, loc, BUILD_STRING, value_count); + } + else if (value_count == 0) { + _Py_DECLARE_STR(empty, ""); + ADDOP_LOAD_CONST_NEW(c, loc, Py_NewRef(&_Py_STR(empty))); } } return SUCCESS; @@ -5000,26 +5133,26 @@ compiler_formatted_value(struct compiler *c, expr_ty e) /* The expression to be formatted. */ VISIT(c, expr, e->v.FormattedValue.value); - switch (conversion) { - case 's': oparg = FVC_STR; break; - case 'r': oparg = FVC_REPR; break; - case 'a': oparg = FVC_ASCII; break; - case -1: oparg = FVC_NONE; break; - default: - PyErr_Format(PyExc_SystemError, + location loc = LOC(e); + if (conversion != -1) { + switch (conversion) { + case 's': oparg = FVC_STR; break; + case 'r': oparg = FVC_REPR; break; + case 'a': oparg = FVC_ASCII; break; + default: + PyErr_Format(PyExc_SystemError, "Unrecognized conversion character %d", conversion); - return ERROR; + return ERROR; + } + ADDOP_I(c, loc, CONVERT_VALUE, oparg); } if (e->v.FormattedValue.format_spec) { /* Evaluate the format spec, and update our opcode arg. */ VISIT(c, expr, e->v.FormattedValue.format_spec); - oparg |= FVS_HAVE_SPEC; + ADDOP(c, loc, FORMAT_WITH_SPEC); + } else { + ADDOP(c, loc, FORMAT_SIMPLE); } - - /* And push our opcode and oparg */ - location loc = LOC(e); - ADDOP_I(c, loc, FORMAT_VALUE, oparg); - return SUCCESS; } @@ -5068,7 +5201,7 @@ compiler_subkwargs(struct compiler *c, location loc, } /* Used by compiler_call_helper and maybe_optimize_method_call to emit - * KW_NAMES before CALL. + * a tuple of keyword names before CALL. */ static int compiler_call_simple_kw_helper(struct compiler *c, location loc, @@ -5083,12 +5216,7 @@ compiler_call_simple_kw_helper(struct compiler *c, location loc, keyword_ty kw = asdl_seq_GET(keywords, i); PyTuple_SET_ITEM(names, i, Py_NewRef(kw->arg)); } - Py_ssize_t arg = compiler_add_const(c->c_const_cache, c->u, names); - if (arg < 0) { - return ERROR; - } - Py_DECREF(names); - ADDOP_I(c, loc, KW_NAMES, arg); + ADDOP_LOAD_CONST_NEW(c, loc, names); return SUCCESS; } @@ -5133,8 +5261,11 @@ compiler_call_helper(struct compiler *c, location loc, VISIT_SEQ(c, keyword, keywords); RETURN_IF_ERROR( compiler_call_simple_kw_helper(c, loc, keywords, nkwelts)); + ADDOP_I(c, loc, CALL_KW, n + nelts + nkwelts); + } + else { + ADDOP_I(c, loc, CALL, n + nelts); } - ADDOP_I(c, loc, CALL, n + nelts + nkwelts); return SUCCESS; ex_call: @@ -5283,6 +5414,7 @@ compiler_sync_comprehension_generator(struct compiler *c, location loc, if (IS_LABEL(start)) { depth++; + ADDOP(c, LOC(gen->iter), GET_ITER); USE_LABEL(c, start); ADDOP_JUMP(c, LOC(gen->iter), FOR_ITER, anchor); } @@ -5342,7 +5474,12 @@ compiler_sync_comprehension_generator(struct compiler *c, location loc, ADDOP_JUMP(c, elt_loc, JUMP, start); USE_LABEL(c, anchor); + /* It is important for instrumentation that the `END_FOR` comes first. + * Iteration over a generator will jump to the first of these instructions, + * but a non-generator will jump to a later instruction. + */ ADDOP(c, NO_LOCATION, END_FOR); + ADDOP(c, NO_LOCATION, POP_TOP); } return SUCCESS; @@ -5515,8 +5652,13 @@ push_inlined_comprehension_state(struct compiler *c, location loc, if ((symbol & DEF_LOCAL && !(symbol & DEF_NONLOCAL)) || in_class_block) { if (!_PyST_IsFunctionLike(c->u->u_ste)) { // non-function scope: override this name to use fast locals - PyObject *orig = PyDict_GetItem(c->u->u_metadata.u_fasthidden, k); - if (orig != Py_True) { + PyObject *orig; + if (PyDict_GetItemRef(c->u->u_metadata.u_fasthidden, k, &orig) < 0) { + return ERROR; + } + int orig_is_true = (orig == Py_True); + Py_XDECREF(orig); + if (!orig_is_true) { if (PyDict_SetItem(c->u->u_metadata.u_fasthidden, k, Py_True) < 0) { return ERROR; } @@ -5618,7 +5760,7 @@ pop_inlined_comprehension_state(struct compiler *c, location loc, } if (state.pushed_locals) { ADDOP(c, NO_LOCATION, POP_BLOCK); - ADDOP_JUMP(c, NO_LOCATION, JUMP, state.end); + ADDOP_JUMP(c, NO_LOCATION, JUMP_NO_INTERRUPT, state.end); // cleanup from an exception inside the comprehension USE_LABEL(c, state.cleanup); @@ -5678,7 +5820,7 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, comprehension_ty outermost; int scope_type = c->u->u_scope_type; int is_top_level_await = IS_TOP_LEVEL_AWAIT(c); - PySTEntryObject *entry = PySymtable_Lookup(c->c_st, (void *)e); + PySTEntryObject *entry = _PySymtable_Lookup(c->c_st, (void *)e); if (entry == NULL) { goto error; } @@ -5854,6 +5996,7 @@ compiler_visit_keyword(struct compiler *c, keyword_ty k) static int compiler_with_except_finish(struct compiler *c, jump_target_label cleanup) { NEW_JUMP_TARGET_LABEL(c, suppress); + ADDOP(c, NO_LOCATION, TO_BOOL); ADDOP_JUMP(c, NO_LOCATION, POP_JUMP_IF_TRUE, suppress); ADDOP_I(c, NO_LOCATION, RERAISE, 2); @@ -5864,7 +6007,7 @@ compiler_with_except_finish(struct compiler *c, jump_target_label cleanup) { ADDOP(c, NO_LOCATION, POP_TOP); ADDOP(c, NO_LOCATION, POP_TOP); NEW_JUMP_TARGET_LABEL(c, exit); - ADDOP_JUMP(c, NO_LOCATION, JUMP, exit); + ADDOP_JUMP(c, NO_LOCATION, JUMP_NO_INTERRUPT, exit); USE_LABEL(c, cleanup); POP_EXCEPT_AND_RERAISE(c, NO_LOCATION); @@ -6086,6 +6229,10 @@ compiler_visit_expr1(struct compiler *c, expr_ty e) if (e->v.UnaryOp.op == UAdd) { ADDOP_I(c, loc, CALL_INTRINSIC_1, INTRINSIC_UNARY_POSITIVE); } + else if (e->v.UnaryOp.op == Not) { + ADDOP(c, loc, TO_BOOL); + ADDOP(c, loc, UNARY_NOT); + } else { ADDOP(c, loc, unaryop(e->v.UnaryOp.op)); } @@ -6169,6 +6316,7 @@ compiler_visit_expr1(struct compiler *c, expr_ty e) ADDOP(c, loc, NOP); return SUCCESS; } + RETURN_IF_ERROR(compiler_maybe_add_static_attribute_to_class(c, e)); VISIT(c, expr, e->v.Attribute.value); loc = LOC(e); loc = update_start_location_to_match_attr(c, loc, e); @@ -6444,7 +6592,7 @@ compiler_error(struct compiler *c, location loc, } PyObject *loc_obj = PyErr_ProgramTextObject(c->c_filename, loc.lineno); if (loc_obj == NULL) { - loc_obj = Py_NewRef(Py_None); + loc_obj = Py_None; } PyObject *args = Py_BuildValue("O(OiiOii)", msg, c->c_filename, loc.lineno, loc.col_offset + 1, loc_obj, @@ -6468,6 +6616,9 @@ static int compiler_warn(struct compiler *c, location loc, const char *format, ...) { + if (c->c_disable_warning) { + return SUCCESS; + } va_list vargs; va_start(vargs, format); PyObject *msg = PyUnicode_FromFormatV(format, vargs); @@ -6475,8 +6626,8 @@ compiler_warn(struct compiler *c, location loc, if (msg == NULL) { return ERROR; } - if (PyErr_WarnExplicitObject(PyExc_SyntaxWarning, msg, c->c_filename, - loc.lineno, NULL, NULL) < 0) + if (PyErr_WarnExplicitObject(PyExc_SyntaxWarning, msg, + c->c_filename, loc.lineno, NULL, NULL) < 0) { if (PyErr_ExceptionMatches(PyExc_SyntaxWarning)) { /* Replace the SyntaxWarning exception with a SyntaxError @@ -6590,7 +6741,7 @@ ensure_fail_pop(struct compiler *c, pattern_context *pc, Py_ssize_t n) return SUCCESS; } Py_ssize_t needed = sizeof(jump_target_label) * size; - jump_target_label *resized = PyObject_Realloc(pc->fail_pop, needed); + jump_target_label *resized = PyMem_Realloc(pc->fail_pop, needed); if (resized == NULL) { PyErr_NoMemory(); return ERROR; @@ -6629,13 +6780,13 @@ emit_and_reset_fail_pop(struct compiler *c, location loc, USE_LABEL(c, pc->fail_pop[pc->fail_pop_size]); if (codegen_addop_noarg(INSTR_SEQUENCE(c), POP_TOP, loc) < 0) { pc->fail_pop_size = 0; - PyObject_Free(pc->fail_pop); + PyMem_Free(pc->fail_pop); pc->fail_pop = NULL; return ERROR; } } USE_LABEL(c, pc->fail_pop[0]); - PyObject_Free(pc->fail_pop); + PyMem_Free(pc->fail_pop); pc->fail_pop = NULL; return SUCCESS; } @@ -7139,7 +7290,7 @@ compiler_pattern_or(struct compiler *c, pattern_ty p, pattern_context *pc) Py_DECREF(pc->stores); *pc = old_pc; Py_INCREF(pc->stores); - // Need to NULL this for the PyObject_Free call in the error block. + // Need to NULL this for the PyMem_Free call in the error block. old_pc.fail_pop = NULL; // No match. Pop the remaining copy of the subject and fail: if (codegen_addop_noarg(INSTR_SEQUENCE(c), POP_TOP, LOC(p)) < 0 || @@ -7185,7 +7336,7 @@ compiler_pattern_or(struct compiler *c, pattern_ty p, pattern_context *pc) diff: compiler_error(c, LOC(p), "alternative patterns bind different names"); error: - PyObject_Free(old_pc.fail_pop); + PyMem_Free(old_pc.fail_pop); Py_DECREF(old_pc.stores); Py_XDECREF(control); return ERROR; @@ -7261,6 +7412,7 @@ compiler_pattern_value(struct compiler *c, pattern_ty p, pattern_context *pc) } VISIT(c, expr, value); ADDOP_COMPARE(c, LOC(p), Eq); + ADDOP(c, LOC(p), TO_BOOL); RETURN_IF_ERROR(jump_to_fail_pop(c, LOC(p), pc, POP_JUMP_IF_FALSE)); return SUCCESS; } @@ -7385,7 +7537,7 @@ compiler_match(struct compiler *c, stmt_ty s) pattern_context pc; pc.fail_pop = NULL; int result = compiler_match_inner(c, s, &pc); - PyObject_Free(pc.fail_pop); + PyMem_Free(pc.fail_pop); return result; } @@ -7460,214 +7612,30 @@ _PyCompile_ConstCacheMergeOne(PyObject *const_cache, PyObject **obj) return ERROR; } - // t is borrowed reference - PyObject *t = PyDict_SetDefault(const_cache, key, key); + PyObject *t; + int res = PyDict_SetDefaultRef(const_cache, key, key, &t); Py_DECREF(key); - if (t == NULL) { + if (res < 0) { return ERROR; } - if (t == key) { // obj is new constant. + if (res == 0) { // inserted: obj is new constant. + Py_DECREF(t); return SUCCESS; } if (PyTuple_CheckExact(t)) { - // t is still borrowed reference - t = PyTuple_GET_ITEM(t, 1); - } - - Py_SETREF(*obj, Py_NewRef(t)); - return SUCCESS; -} - - -static int * -build_cellfixedoffsets(_PyCompile_CodeUnitMetadata *umd) -{ - int nlocals = (int)PyDict_GET_SIZE(umd->u_varnames); - int ncellvars = (int)PyDict_GET_SIZE(umd->u_cellvars); - int nfreevars = (int)PyDict_GET_SIZE(umd->u_freevars); - - int noffsets = ncellvars + nfreevars; - int *fixed = PyMem_New(int, noffsets); - if (fixed == NULL) { - PyErr_NoMemory(); - return NULL; - } - for (int i = 0; i < noffsets; i++) { - fixed[i] = nlocals + i; - } - - PyObject *varname, *cellindex; - Py_ssize_t pos = 0; - while (PyDict_Next(umd->u_cellvars, &pos, &varname, &cellindex)) { - PyObject *varindex = PyDict_GetItem(umd->u_varnames, varname); - if (varindex != NULL) { - assert(PyLong_AS_LONG(cellindex) < INT_MAX); - assert(PyLong_AS_LONG(varindex) < INT_MAX); - int oldindex = (int)PyLong_AS_LONG(cellindex); - int argoffset = (int)PyLong_AS_LONG(varindex); - fixed[oldindex] = argoffset; - } + PyObject *item = PyTuple_GET_ITEM(t, 1); + Py_SETREF(*obj, Py_NewRef(item)); + Py_DECREF(t); } - - return fixed; -} - -static int -insert_prefix_instructions(_PyCompile_CodeUnitMetadata *umd, basicblock *entryblock, - int *fixed, int nfreevars, int code_flags) -{ - assert(umd->u_firstlineno > 0); - - /* Add the generator prefix instructions. */ - if (code_flags & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR)) { - cfg_instr make_gen = { - .i_opcode = RETURN_GENERATOR, - .i_oparg = 0, - .i_loc = LOCATION(umd->u_firstlineno, umd->u_firstlineno, -1, -1), - .i_target = NULL, - }; - RETURN_IF_ERROR(_PyBasicblock_InsertInstruction(entryblock, 0, &make_gen)); - cfg_instr pop_top = { - .i_opcode = POP_TOP, - .i_oparg = 0, - .i_loc = NO_LOCATION, - .i_target = NULL, - }; - RETURN_IF_ERROR(_PyBasicblock_InsertInstruction(entryblock, 1, &pop_top)); - } - - /* Set up cells for any variable that escapes, to be put in a closure. */ - const int ncellvars = (int)PyDict_GET_SIZE(umd->u_cellvars); - if (ncellvars) { - // umd->u_cellvars has the cells out of order so we sort them - // before adding the MAKE_CELL instructions. Note that we - // adjust for arg cells, which come first. - const int nvars = ncellvars + (int)PyDict_GET_SIZE(umd->u_varnames); - int *sorted = PyMem_RawCalloc(nvars, sizeof(int)); - if (sorted == NULL) { - PyErr_NoMemory(); - return ERROR; - } - for (int i = 0; i < ncellvars; i++) { - sorted[fixed[i]] = i + 1; - } - for (int i = 0, ncellsused = 0; ncellsused < ncellvars; i++) { - int oldindex = sorted[i] - 1; - if (oldindex == -1) { - continue; - } - cfg_instr make_cell = { - .i_opcode = MAKE_CELL, - // This will get fixed in offset_derefs(). - .i_oparg = oldindex, - .i_loc = NO_LOCATION, - .i_target = NULL, - }; - if (_PyBasicblock_InsertInstruction(entryblock, ncellsused, &make_cell) < 0) { - PyMem_RawFree(sorted); - return ERROR; - } - ncellsused += 1; - } - PyMem_RawFree(sorted); - } - - if (nfreevars) { - cfg_instr copy_frees = { - .i_opcode = COPY_FREE_VARS, - .i_oparg = nfreevars, - .i_loc = NO_LOCATION, - .i_target = NULL, - }; - RETURN_IF_ERROR(_PyBasicblock_InsertInstruction(entryblock, 0, ©_frees)); + else { + Py_SETREF(*obj, t); } return SUCCESS; } static int -fix_cell_offsets(_PyCompile_CodeUnitMetadata *umd, basicblock *entryblock, int *fixedmap) -{ - int nlocals = (int)PyDict_GET_SIZE(umd->u_varnames); - int ncellvars = (int)PyDict_GET_SIZE(umd->u_cellvars); - int nfreevars = (int)PyDict_GET_SIZE(umd->u_freevars); - int noffsets = ncellvars + nfreevars; - - // First deal with duplicates (arg cells). - int numdropped = 0; - for (int i = 0; i < noffsets ; i++) { - if (fixedmap[i] == i + nlocals) { - fixedmap[i] -= numdropped; - } - else { - // It was a duplicate (cell/arg). - numdropped += 1; - } - } - - // Then update offsets, either relative to locals or by cell2arg. - for (basicblock *b = entryblock; b != NULL; b = b->b_next) { - for (int i = 0; i < b->b_iused; i++) { - cfg_instr *inst = &b->b_instr[i]; - // This is called before extended args are generated. - assert(inst->i_opcode != EXTENDED_ARG); - int oldoffset = inst->i_oparg; - switch(inst->i_opcode) { - case MAKE_CELL: - case LOAD_CLOSURE: - case LOAD_DEREF: - case STORE_DEREF: - case DELETE_DEREF: - case LOAD_FROM_DICT_OR_DEREF: - assert(oldoffset >= 0); - assert(oldoffset < noffsets); - assert(fixedmap[oldoffset] >= 0); - inst->i_oparg = fixedmap[oldoffset]; - } - } - } - - return numdropped; -} - - -static int -prepare_localsplus(_PyCompile_CodeUnitMetadata *umd, cfg_builder *g, int code_flags) -{ - assert(PyDict_GET_SIZE(umd->u_varnames) < INT_MAX); - assert(PyDict_GET_SIZE(umd->u_cellvars) < INT_MAX); - assert(PyDict_GET_SIZE(umd->u_freevars) < INT_MAX); - int nlocals = (int)PyDict_GET_SIZE(umd->u_varnames); - int ncellvars = (int)PyDict_GET_SIZE(umd->u_cellvars); - int nfreevars = (int)PyDict_GET_SIZE(umd->u_freevars); - assert(INT_MAX - nlocals - ncellvars > 0); - assert(INT_MAX - nlocals - ncellvars - nfreevars > 0); - int nlocalsplus = nlocals + ncellvars + nfreevars; - int* cellfixedoffsets = build_cellfixedoffsets(umd); - if (cellfixedoffsets == NULL) { - return ERROR; - } - - - // This must be called before fix_cell_offsets(). - if (insert_prefix_instructions(umd, g->g_entryblock, cellfixedoffsets, nfreevars, code_flags)) { - PyMem_Free(cellfixedoffsets); - return ERROR; - } - - int numdropped = fix_cell_offsets(umd, g->g_entryblock, cellfixedoffsets); - PyMem_Free(cellfixedoffsets); // At this point we're done with it. - cellfixedoffsets = NULL; - if (numdropped < 0) { - return ERROR; - } - - nlocalsplus -= numdropped; - return nlocalsplus; -} - -static int add_return_at_end(struct compiler *c, int addNone) { /* Make sure every instruction stream that falls off the end returns None. @@ -7680,65 +7648,50 @@ add_return_at_end(struct compiler *c, int addNone) return SUCCESS; } -static int cfg_to_instr_sequence(cfg_builder *g, instr_sequence *seq); - static PyCodeObject * optimize_and_assemble_code_unit(struct compiler_unit *u, PyObject *const_cache, int code_flags, PyObject *filename) { + cfg_builder *g = NULL; instr_sequence optimized_instrs; memset(&optimized_instrs, 0, sizeof(instr_sequence)); PyCodeObject *co = NULL; PyObject *consts = consts_dict_keys_inorder(u->u_metadata.u_consts); if (consts == NULL) { - return NULL; + goto error; } - cfg_builder g; - if (instr_sequence_to_cfg(&u->u_instr_sequence, &g) < 0) { + g = instr_sequence_to_cfg(u->u_instr_sequence); + if (g == NULL) { goto error; } - int nparams = (int)PyList_GET_SIZE(u->u_ste->ste_varnames); int nlocals = (int)PyDict_GET_SIZE(u->u_metadata.u_varnames); + int nparams = (int)PyList_GET_SIZE(u->u_ste->ste_varnames); assert(u->u_metadata.u_firstlineno); - if (_PyCfg_OptimizeCodeUnit(&g, consts, const_cache, code_flags, nlocals, - nparams, u->u_metadata.u_firstlineno) < 0) { - goto error; - } - - /** Assembly **/ - int nlocalsplus = prepare_localsplus(&u->u_metadata, &g, code_flags); - if (nlocalsplus < 0) { - goto error; - } - int maxdepth = _PyCfg_Stackdepth(g.g_entryblock, code_flags); - if (maxdepth < 0) { + if (_PyCfg_OptimizeCodeUnit(g, consts, const_cache, nlocals, + nparams, u->u_metadata.u_firstlineno) < 0) { goto error; } - _PyCfg_ConvertPseudoOps(g.g_entryblock); - - /* Order of basic blocks must have been determined by now */ - - if (_PyCfg_ResolveJumps(&g) < 0) { + int stackdepth; + int nlocalsplus; + if (_PyCfg_OptimizedCfgToInstructionSequence(g, &u->u_metadata, code_flags, + &stackdepth, &nlocalsplus, + &optimized_instrs) < 0) { goto error; } - /* Can't modify the bytecode after computing jump offsets. */ - - if (cfg_to_instr_sequence(&g, &optimized_instrs) < 0) { - goto error; - } + /** Assembly **/ co = _PyAssemble_MakeCodeObject(&u->u_metadata, const_cache, consts, - maxdepth, &optimized_instrs, nlocalsplus, + stackdepth, &optimized_instrs, nlocalsplus, code_flags, filename); error: Py_XDECREF(consts); - instr_sequence_fini(&optimized_instrs); - _PyCfgBuilder_Fini(&g); + PyInstructionSequence_Fini(&optimized_instrs); + _PyCfgBuilder_Free(g); return co; } @@ -7761,36 +7714,6 @@ optimize_and_assemble(struct compiler *c, int addNone) return optimize_and_assemble_code_unit(u, const_cache, code_flags, filename); } -static int -cfg_to_instr_sequence(cfg_builder *g, instr_sequence *seq) -{ - int lbl = 0; - for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { - b->b_label = (jump_target_label){lbl}; - lbl += b->b_iused; - } - for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { - RETURN_IF_ERROR(instr_sequence_use_label(seq, b->b_label.id)); - for (int i = 0; i < b->b_iused; i++) { - cfg_instr *instr = &b->b_instr[i]; - RETURN_IF_ERROR( - instr_sequence_addop(seq, instr->i_opcode, instr->i_oparg, instr->i_loc)); - - _PyCompile_ExceptHandlerInfo *hi = &seq->s_instrs[seq->s_used-1].i_except_handler_info; - if (instr->i_except != NULL) { - hi->h_offset = instr->i_except->b_offset; - hi->h_startdepth = instr->i_except->b_startdepth; - hi->h_preserve_lasti = instr->i_except->b_preserve_lasti; - } - else { - hi->h_offset = -1; - } - } - } - return SUCCESS; -} - - /* Access to compiler optimizations for unit tests. * * _PyCompile_CodeGen takes and AST, applies code-gen and @@ -7805,185 +7728,116 @@ cfg_to_instr_sequence(cfg_builder *g, instr_sequence *seq) * a jump target label marking the beginning of a basic block. */ -static int -instructions_to_instr_sequence(PyObject *instructions, instr_sequence *seq) -{ - assert(PyList_Check(instructions)); - - Py_ssize_t num_insts = PyList_GET_SIZE(instructions); - bool *is_target = PyMem_Calloc(num_insts, sizeof(bool)); - if (is_target == NULL) { - return ERROR; - } - for (Py_ssize_t i = 0; i < num_insts; i++) { - PyObject *item = PyList_GET_ITEM(instructions, i); - if (!PyTuple_Check(item) || PyTuple_GET_SIZE(item) != 6) { - PyErr_SetString(PyExc_ValueError, "expected a 6-tuple"); - goto error; - } - int opcode = PyLong_AsLong(PyTuple_GET_ITEM(item, 0)); - if (PyErr_Occurred()) { - goto error; - } - if (HAS_TARGET(opcode)) { - int oparg = PyLong_AsLong(PyTuple_GET_ITEM(item, 1)); - if (PyErr_Occurred()) { - goto error; - } - if (oparg < 0 || oparg >= num_insts) { - PyErr_SetString(PyExc_ValueError, "label out of range"); - goto error; - } - is_target[oparg] = true; - } - } - for (int i = 0; i < num_insts; i++) { - if (is_target[i]) { - if (instr_sequence_use_label(seq, i) < 0) { - goto error; - } - } - PyObject *item = PyList_GET_ITEM(instructions, i); - if (!PyTuple_Check(item) || PyTuple_GET_SIZE(item) != 6) { - PyErr_SetString(PyExc_ValueError, "expected a 6-tuple"); - goto error; - } - int opcode = PyLong_AsLong(PyTuple_GET_ITEM(item, 0)); - if (PyErr_Occurred()) { - goto error; - } - int oparg; - if (HAS_ARG(opcode)) { - oparg = PyLong_AsLong(PyTuple_GET_ITEM(item, 1)); - if (PyErr_Occurred()) { - goto error; - } - } - else { - oparg = 0; - } - location loc; - loc.lineno = PyLong_AsLong(PyTuple_GET_ITEM(item, 2)); - if (PyErr_Occurred()) { - goto error; - } - loc.end_lineno = PyLong_AsLong(PyTuple_GET_ITEM(item, 3)); - if (PyErr_Occurred()) { - goto error; - } - loc.col_offset = PyLong_AsLong(PyTuple_GET_ITEM(item, 4)); - if (PyErr_Occurred()) { - goto error; - } - loc.end_col_offset = PyLong_AsLong(PyTuple_GET_ITEM(item, 5)); - if (PyErr_Occurred()) { +static PyObject * +cfg_to_instruction_sequence(cfg_builder *g) +{ + instr_sequence *seq = (instr_sequence *)_PyInstructionSequence_New(); + if (seq != NULL) { + if (_PyCfg_ToInstructionSequence(g, seq) < 0) { goto error; } - if (instr_sequence_addop(seq, opcode, oparg, loc) < 0) { + if (_PyInstructionSequence_ApplyLabelMap(seq) < 0) { goto error; } } - PyMem_Free(is_target); - return SUCCESS; + return (PyObject*)seq; error: - PyMem_Free(is_target); - return ERROR; + PyInstructionSequence_Fini(seq); + return NULL; } -static int -instructions_to_cfg(PyObject *instructions, cfg_builder *g) +// C implementation of inspect.cleandoc() +// +// Difference from inspect.cleandoc(): +// - Do not remove leading and trailing blank lines to keep lineno. +PyObject * +_PyCompile_CleanDoc(PyObject *doc) { - instr_sequence seq; - memset(&seq, 0, sizeof(instr_sequence)); - - if (instructions_to_instr_sequence(instructions, &seq) < 0) { - goto error; - } - if (instr_sequence_to_cfg(&seq, g) < 0) { - goto error; + doc = PyObject_CallMethod(doc, "expandtabs", NULL); + if (doc == NULL) { + return NULL; } - instr_sequence_fini(&seq); - return SUCCESS; -error: - instr_sequence_fini(&seq); - return ERROR; -} -static PyObject * -instr_sequence_to_instructions(instr_sequence *seq) -{ - PyObject *instructions = PyList_New(0); - if (instructions == NULL) { + Py_ssize_t doc_size; + const char *doc_utf8 = PyUnicode_AsUTF8AndSize(doc, &doc_size); + if (doc_utf8 == NULL) { + Py_DECREF(doc); return NULL; } - for (int i = 0; i < seq->s_used; i++) { - instruction *instr = &seq->s_instrs[i]; - location loc = instr->i_loc; - int arg = HAS_TARGET(instr->i_opcode) ? - seq->s_labelmap[instr->i_oparg] : instr->i_oparg; + const char *p = doc_utf8; + const char *pend = p + doc_size; - PyObject *inst_tuple = Py_BuildValue( - "(iiiiii)", instr->i_opcode, arg, - loc.lineno, loc.end_lineno, - loc.col_offset, loc.end_col_offset); - if (inst_tuple == NULL) { - goto error; - } + // First pass: find minimum indentation of any non-blank lines + // after first line. + while (p < pend && *p++ != '\n') { + } - int res = PyList_Append(instructions, inst_tuple); - Py_DECREF(inst_tuple); - if (res != 0) { - goto error; + Py_ssize_t margin = PY_SSIZE_T_MAX; + while (p < pend) { + const char *s = p; + while (*p == ' ') p++; + if (p < pend && *p != '\n') { + margin = Py_MIN(margin, p - s); + } + while (p < pend && *p++ != '\n') { } } - return instructions; -error: - Py_XDECREF(instructions); - return NULL; -} + if (margin == PY_SSIZE_T_MAX) { + margin = 0; + } -static PyObject * -cfg_to_instructions(cfg_builder *g) -{ - PyObject *instructions = PyList_New(0); - if (instructions == NULL) { + // Second pass: write cleandoc into buff. + + // copy first line without leading spaces. + p = doc_utf8; + while (*p == ' ') { + p++; + } + if (p == doc_utf8 && margin == 0 ) { + // doc is already clean. + return doc; + } + + char *buff = PyMem_Malloc(doc_size); + if (buff == NULL){ + Py_DECREF(doc); + PyErr_NoMemory(); return NULL; } - int lbl = 0; - for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { - b->b_label = (jump_target_label){lbl}; - lbl += b->b_iused; + + char *w = buff; + + while (p < pend) { + int ch = *w++ = *p++; + if (ch == '\n') { + break; + } } - for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { - for (int i = 0; i < b->b_iused; i++) { - cfg_instr *instr = &b->b_instr[i]; - location loc = instr->i_loc; - int arg = HAS_TARGET(instr->i_opcode) ? - instr->i_target->b_label.id : instr->i_oparg; - PyObject *inst_tuple = Py_BuildValue( - "(iiiiii)", instr->i_opcode, arg, - loc.lineno, loc.end_lineno, - loc.col_offset, loc.end_col_offset); - if (inst_tuple == NULL) { - goto error; + // copy subsequent lines without margin. + while (p < pend) { + for (Py_ssize_t i = 0; i < margin; i++, p++) { + if (*p != ' ') { + assert(*p == '\n' || *p == '\0'); + break; } - - if (PyList_Append(instructions, inst_tuple) != 0) { - Py_DECREF(inst_tuple); - goto error; + } + while (p < pend) { + int ch = *w++ = *p++; + if (ch == '\n') { + break; } - Py_DECREF(inst_tuple); } } - return instructions; -error: - Py_DECREF(instructions); - return NULL; + Py_DECREF(doc); + PyObject *res = PyUnicode_FromStringAndSize(buff, w - buff); + PyMem_Free(buff); + return res; } + PyObject * _PyCompile_CodeGen(PyObject *ast, PyObject *filename, PyCompilerFlags *pflags, int optimize, int compile_mode) @@ -8012,16 +7866,22 @@ _PyCompile_CodeGen(PyObject *ast, PyObject *filename, PyCompilerFlags *pflags, _PyArena_Free(arena); return NULL; } + c->c_save_nested_seqs = true; + metadata = PyDict_New(); + if (metadata == NULL) { + return NULL; + } + + if (compiler_enter_anonymous_scope(c, mod) < 0) { + return NULL; + } if (compiler_codegen(c, mod) < 0) { goto finally; } _PyCompile_CodeUnitMetadata *umd = &c->u->u_metadata; - metadata = PyDict_New(); - if (metadata == NULL) { - goto finally; - } + #define SET_MATADATA_ITEM(key, value) \ if (value != NULL) { \ if (PyDict_SetItemString(metadata, key, value) < 0) goto finally; \ @@ -8054,12 +7914,11 @@ _PyCompile_CodeGen(PyObject *ast, PyObject *filename, PyCompilerFlags *pflags, goto finally; } - PyObject *insts = instr_sequence_to_instructions(INSTR_SEQUENCE(c)); - if (insts == NULL) { - goto finally; + if (_PyInstructionSequence_ApplyLabelMap(INSTR_SEQUENCE(c)) < 0) { + return NULL; } - res = PyTuple_Pack(2, insts, metadata); - Py_DECREF(insts); + /* Allocate a copy of the instruction sequence on the heap */ + res = PyTuple_Pack(2, INSTR_SEQUENCE(c), metadata); finally: Py_XDECREF(metadata); @@ -8070,36 +7929,45 @@ finally: } PyObject * -_PyCompile_OptimizeCfg(PyObject *instructions, PyObject *consts, int nlocals) +_PyCompile_OptimizeCfg(PyObject *seq, PyObject *consts, int nlocals) { - PyObject *res = NULL; + if (!_PyInstructionSequence_Check(seq)) { + PyErr_SetString(PyExc_ValueError, "expected an instruction sequence"); + return NULL; + } PyObject *const_cache = PyDict_New(); if (const_cache == NULL) { return NULL; } - cfg_builder g; - if (instructions_to_cfg(instructions, &g) < 0) { + PyObject *res = NULL; + cfg_builder *g = instr_sequence_to_cfg((instr_sequence*)seq); + if (g == NULL) { goto error; } - int code_flags = 0, nparams = 0, firstlineno = 1; - if (_PyCfg_OptimizeCodeUnit(&g, consts, const_cache, code_flags, nlocals, + int nparams = 0, firstlineno = 1; + if (_PyCfg_OptimizeCodeUnit(g, consts, const_cache, nlocals, nparams, firstlineno) < 0) { goto error; } - res = cfg_to_instructions(&g); + res = cfg_to_instruction_sequence(g); error: Py_DECREF(const_cache); - _PyCfgBuilder_Fini(&g); + _PyCfgBuilder_Free(g); return res; } -int _PyCfg_JumpLabelsToTargets(basicblock *entryblock); +int _PyCfg_JumpLabelsToTargets(cfg_builder *g); PyCodeObject * _PyCompile_Assemble(_PyCompile_CodeUnitMetadata *umd, PyObject *filename, - PyObject *instructions) + PyObject *seq) { + if (!_PyInstructionSequence_Check(seq)) { + PyErr_SetString(PyExc_TypeError, "expected an instruction sequence"); + return NULL; + } + cfg_builder *g = NULL; PyCodeObject *co = NULL; instr_sequence optimized_instrs; memset(&optimized_instrs, 0, sizeof(instr_sequence)); @@ -8109,37 +7977,20 @@ _PyCompile_Assemble(_PyCompile_CodeUnitMetadata *umd, PyObject *filename, return NULL; } - cfg_builder g; - if (instructions_to_cfg(instructions, &g) < 0) { + g = instr_sequence_to_cfg((instr_sequence*)seq); + if (g == NULL) { goto error; } - if (_PyCfg_JumpLabelsToTargets(g.g_entryblock) < 0) { + if (_PyCfg_JumpLabelsToTargets(g) < 0) { goto error; } int code_flags = 0; - int nlocalsplus = prepare_localsplus(umd, &g, code_flags); - if (nlocalsplus < 0) { - goto error; - } - - int maxdepth = _PyCfg_Stackdepth(g.g_entryblock, code_flags); - if (maxdepth < 0) { - goto error; - } - - _PyCfg_ConvertPseudoOps(g.g_entryblock); - - /* Order of basic blocks must have been determined by now */ - - if (_PyCfg_ResolveJumps(&g) < 0) { - goto error; - } - - /* Can't modify the bytecode after computing jump offsets. */ - - if (cfg_to_instr_sequence(&g, &optimized_instrs) < 0) { + int stackdepth, nlocalsplus; + if (_PyCfg_OptimizedCfgToInstructionSequence(g, umd, code_flags, + &stackdepth, &nlocalsplus, + &optimized_instrs) < 0) { goto error; } @@ -8148,14 +7999,14 @@ _PyCompile_Assemble(_PyCompile_CodeUnitMetadata *umd, PyObject *filename, goto error; } co = _PyAssemble_MakeCodeObject(umd, const_cache, - consts, maxdepth, &optimized_instrs, + consts, stackdepth, &optimized_instrs, nlocalsplus, code_flags, filename); Py_DECREF(consts); error: Py_DECREF(const_cache); - _PyCfgBuilder_Fini(&g); - instr_sequence_fini(&optimized_instrs); + _PyCfgBuilder_Free(g); + PyInstructionSequence_Fini(&optimized_instrs); return co; } |
