summaryrefslogtreecommitdiffstats
path: root/contrib/tools/python3/Python/compile.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/tools/python3/Python/compile.c')
-rw-r--r--contrib/tools/python3/Python/compile.c1509
1 files changed, 680 insertions, 829 deletions
diff --git a/contrib/tools/python3/Python/compile.c b/contrib/tools/python3/Python/compile.c
index 56fdbfae6f6..8f8b6773440 100644
--- a/contrib/tools/python3/Python/compile.c
+++ b/contrib/tools/python3/Python/compile.c
@@ -21,26 +21,25 @@
* objects.
*/
-#include <stdbool.h>
-
#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
-
-#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, &copy_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;
}