Mailing List Archive

gh-117494: extract the Instruction Sequence data structure into a separate file (#117496)
https://github.com/python/cpython/commit/04697bcfaf5dd34c9312f4f405083b6d33b3511f
commit: 04697bcfaf5dd34c9312f4f405083b6d33b3511f
branch: main
author: Irit Katriel <1055913+iritkatriel@users.noreply.github.com>
committer: iritkatriel <1055913+iritkatriel@users.noreply.github.com>
date: 2024-04-04T15:47:26Z
summary:

gh-117494: extract the Instruction Sequence data structure into a separate file (#117496)

files:
A Include/internal/pycore_instruction_sequence.h
A Misc/NEWS.d/next/Core and Builtins/2024-04-04-13-42-59.gh-issue-117494.GPQH64.rst
A Python/instruction_sequence.c
M Include/internal/pycore_compile.h
M Include/internal/pycore_flowgraph.h
M Makefile.pre.in
M PCbuild/_freeze_module.vcxproj
M PCbuild/_freeze_module.vcxproj.filters
M PCbuild/pythoncore.vcxproj
M PCbuild/pythoncore.vcxproj.filters
M Python/assemble.c
M Python/compile.c
M Python/flowgraph.c

diff --git a/Include/internal/pycore_compile.h b/Include/internal/pycore_compile.h
index eb6e5ca58f7390..3c21f83a18b52a 100644
--- a/Include/internal/pycore_compile.h
+++ b/Include/internal/pycore_compile.h
@@ -9,6 +9,7 @@ extern "C" {
#endif

#include "pycore_symtable.h" // _Py_SourceLocation
+#include "pycore_instruction_sequence.h"

struct _arena; // Type defined in pycore_pyarena.h
struct _mod; // Type defined in pycore_ast.h
@@ -37,38 +38,6 @@ extern int _PyAST_Optimize(
int optimize,
int ff_features);

-typedef struct {
- int h_label;
- int h_startdepth;
- int h_preserve_lasti;
-} _PyCompile_ExceptHandlerInfo;
-
-typedef struct {
- int i_opcode;
- int i_oparg;
- _Py_SourceLocation i_loc;
- _PyCompile_ExceptHandlerInfo i_except_handler_info;
-
- /* Used by the assembler */
- int i_target;
- int i_offset;
-} _PyCompile_Instruction;
-
-typedef struct {
- _PyCompile_Instruction *s_instrs;
- int s_allocated;
- int s_used;
-
- int *s_labelmap; /* label id --> instr offset */
- int s_labelmap_size;
- int s_next_free_label; /* next free label id */
-} _PyCompile_InstructionSequence;
-
-int _PyCompile_InstructionSequence_UseLabel(_PyCompile_InstructionSequence *seq, int lbl);
-int _PyCompile_InstructionSequence_Addop(_PyCompile_InstructionSequence *seq,
- int opcode, int oparg,
- _Py_SourceLocation loc);
-int _PyCompile_InstructionSequence_ApplyLabelMap(_PyCompile_InstructionSequence *seq);

typedef struct {
PyObject *u_name;
diff --git a/Include/internal/pycore_flowgraph.h b/Include/internal/pycore_flowgraph.h
index 121302aacb3a8b..819117b83114bc 100644
--- a/Include/internal/pycore_flowgraph.h
+++ b/Include/internal/pycore_flowgraph.h
@@ -8,16 +8,13 @@ extern "C" {
# error "this header requires Py_BUILD_CORE define"
#endif

-#include "pycore_opcode_utils.h"
#include "pycore_compile.h"
-
-typedef struct {
- int id;
-} _PyCfgJumpTargetLabel;
+#include "pycore_instruction_sequence.h"
+#include "pycore_opcode_utils.h"

struct _PyCfgBuilder;

-int _PyCfgBuilder_UseLabel(struct _PyCfgBuilder *g, _PyCfgJumpTargetLabel lbl);
+int _PyCfgBuilder_UseLabel(struct _PyCfgBuilder *g, _PyJumpTargetLabel lbl);
int _PyCfgBuilder_Addop(struct _PyCfgBuilder *g, int opcode, int oparg, _Py_SourceLocation loc);

struct _PyCfgBuilder* _PyCfgBuilder_New(void);
@@ -27,14 +24,14 @@ int _PyCfgBuilder_CheckSize(struct _PyCfgBuilder* g);
int _PyCfg_OptimizeCodeUnit(struct _PyCfgBuilder *g, PyObject *consts, PyObject *const_cache,
int nlocals, int nparams, int firstlineno);

-int _PyCfg_ToInstructionSequence(struct _PyCfgBuilder *g, _PyCompile_InstructionSequence *seq);
+int _PyCfg_ToInstructionSequence(struct _PyCfgBuilder *g, _PyInstructionSequence *seq);
int _PyCfg_OptimizedCfgToInstructionSequence(struct _PyCfgBuilder *g, _PyCompile_CodeUnitMetadata *umd,
int code_flags, int *stackdepth, int *nlocalsplus,
- _PyCompile_InstructionSequence *seq);
+ _PyInstructionSequence *seq);

PyCodeObject *
_PyAssemble_MakeCodeObject(_PyCompile_CodeUnitMetadata *u, PyObject *const_cache,
- PyObject *consts, int maxdepth, _PyCompile_InstructionSequence *instrs,
+ PyObject *consts, int maxdepth, _PyInstructionSequence *instrs,
int nlocalsplus, int code_flags, PyObject *filename);

#ifdef __cplusplus
diff --git a/Include/internal/pycore_instruction_sequence.h b/Include/internal/pycore_instruction_sequence.h
new file mode 100644
index 00000000000000..b57484fa05309f
--- /dev/null
+++ b/Include/internal/pycore_instruction_sequence.h
@@ -0,0 +1,60 @@
+#ifndef Py_INTERNAL_INSTRUCTION_SEQUENCE_H
+#define Py_INTERNAL_INSTRUCTION_SEQUENCE_H
+
+#ifndef Py_BUILD_CORE
+# error "this header requires Py_BUILD_CORE define"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+ int h_label;
+ int h_startdepth;
+ int h_preserve_lasti;
+} _PyExceptHandlerInfo;
+
+typedef struct {
+ int i_opcode;
+ int i_oparg;
+ _Py_SourceLocation i_loc;
+ _PyExceptHandlerInfo i_except_handler_info;
+
+ /* Temporary fields, used by the assembler and in instr_sequence_to_cfg */
+ int i_target;
+ int i_offset;
+} _PyInstruction;
+
+typedef struct {
+ _PyInstruction *s_instrs;
+ int s_allocated;
+ int s_used;
+
+ int s_next_free_label; /* next free label id */
+ /* Map of a label id to instruction offset (index into s_instrs).
+ * If s_labelmap is NULL, then each label id is the offset itself.
+ */
+ int *s_labelmap; /* label id --> instr offset */
+ int s_labelmap_size;
+} _PyInstructionSequence;
+
+typedef struct {
+ int id;
+} _PyJumpTargetLabel;
+
+int _PyInstructionSequence_UseLabel(_PyInstructionSequence *seq, int lbl);
+int _PyInstructionSequence_Addop(_PyInstructionSequence *seq,
+ int opcode, int oparg,
+ _Py_SourceLocation loc);
+_PyJumpTargetLabel _PyInstructionSequence_NewLabel(_PyInstructionSequence *seq);
+int _PyInstructionSequence_ApplyLabelMap(_PyInstructionSequence *seq);
+int _PyInstructionSequence_InsertInstruction(_PyInstructionSequence *seq, int pos,
+ int opcode, int oparg, _Py_SourceLocation loc);
+void PyInstructionSequence_Fini(_PyInstructionSequence *seq);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* !Py_INTERNAL_INSTRUCTION_SEQUENCE_H */
diff --git a/Makefile.pre.in b/Makefile.pre.in
index 84058acdcc35fc..fd8678cdaf8207 100644
--- a/Makefile.pre.in
+++ b/Makefile.pre.in
@@ -442,6 +442,7 @@ PYTHON_OBJS= \
Python/initconfig.o \
Python/interpconfig.o \
Python/instrumentation.o \
+ Python/instruction_sequence.o \
Python/intrinsics.o \
Python/jit.o \
Python/legacy_tracing.o \
@@ -1170,6 +1171,7 @@ PYTHON_HEADERS= \
$(srcdir)/Include/internal/pycore_importdl.h \
$(srcdir)/Include/internal/pycore_initconfig.h \
$(srcdir)/Include/internal/pycore_instruments.h \
+ $(srcdir)/Include/internal/pycore_instruction_sequence.h \
$(srcdir)/Include/internal/pycore_interp.h \
$(srcdir)/Include/internal/pycore_intrinsics.h \
$(srcdir)/Include/internal/pycore_jit.h \
@@ -1800,7 +1802,7 @@ regen-sre:
$(srcdir)/Modules/_sre/sre_constants.h \
$(srcdir)/Modules/_sre/sre_targets.h

-Python/compile.o Python/symtable.o Python/ast_unparse.o Python/ast.o Python/future.o: $(srcdir)/Include/internal/pycore_ast.h
+Python/compile.o Python/symtable.o Python/ast_unparse.o Python/ast.o Python/future.o: $(srcdir)/Include/internal/pycore_ast.h $(srcdir)/Include/internal/pycore_ast.h

Python/getplatform.o: $(srcdir)/Python/getplatform.c
$(CC) -c $(PY_CORE_CFLAGS) -DPLATFORM='"$(MACHDEP)"' -o $@ $(srcdir)/Python/getplatform.c
@@ -1935,8 +1937,12 @@ regen-uop-metadata:
$(srcdir)/Include/internal/pycore_uop_metadata.h.new $(srcdir)/Python/bytecodes.c
$(UPDATE_FILE) $(srcdir)/Include/internal/pycore_uop_metadata.h $(srcdir)/Include/internal/pycore_uop_metadata.h.new

-
-Python/compile.o: $(srcdir)/Include/internal/pycore_opcode_metadata.h
+Python/compile.o Python/assemble.o Python/flowgraph.o Python/instruction_sequence.o: \
+ $(srcdir)/Include/internal/pycore_compile.h \
+ $(srcdir)/Include/internal/pycore_flowgraph.h \
+ $(srcdir)/Include/internal/pycore_instruction_sequence.h \
+ $(srcdir)/Include/internal/pycore_opcode_metadata.h \
+ $(srcdir)/Include/internal/pycore_opcode_utils.h

Python/ceval.o: \
$(srcdir)/Python/ceval_macros.h \
diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-04-04-13-42-59.gh-issue-117494.GPQH64.rst b/Misc/NEWS.d/next/Core and Builtins/2024-04-04-13-42-59.gh-issue-117494.GPQH64.rst
new file mode 100644
index 00000000000000..3b550eda64834b
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2024-04-04-13-42-59.gh-issue-117494.GPQH64.rst
@@ -0,0 +1 @@
+Refactored the instruction sequence data structure out of compile.c into instruction_sequence.c.
diff --git a/PCbuild/_freeze_module.vcxproj b/PCbuild/_freeze_module.vcxproj
index 9c82fcf021bb55..9717d89b54d828 100644
--- a/PCbuild/_freeze_module.vcxproj
+++ b/PCbuild/_freeze_module.vcxproj
@@ -222,6 +222,7 @@
<ClCompile Include="..\Python\import.c" />
<ClCompile Include="..\Python\importdl.c" />
<ClCompile Include="..\Python\initconfig.c" />
+ <ClCompile Include="..\Python\instruction_sequence.c" />
<ClCompile Include="..\Python\interpconfig.c" />
<ClCompile Include="..\Python\intrinsics.c" />
<ClCompile Include="..\Python\instrumentation.c" />
diff --git a/PCbuild/_freeze_module.vcxproj.filters b/PCbuild/_freeze_module.vcxproj.filters
index 63b033a0350b20..9b106bea601e34 100644
--- a/PCbuild/_freeze_module.vcxproj.filters
+++ b/PCbuild/_freeze_module.vcxproj.filters
@@ -229,6 +229,7 @@
<ClCompile Include="..\Python\initconfig.c">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="..\Python\instruction_sequence.c">
<ClCompile Include="..\Python\interpconfig.c">
<Filter>Source Files</Filter>
</ClCompile>
diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj
index 827c9f074de909..3a019a5fe550db 100644
--- a/PCbuild/pythoncore.vcxproj
+++ b/PCbuild/pythoncore.vcxproj
@@ -248,6 +248,7 @@
<ClInclude Include="..\Include\internal\pycore_import.h" />
<ClInclude Include="..\Include\internal\pycore_importdl.h" />
<ClInclude Include="..\Include\internal\pycore_initconfig.h" />
+ <ClInclude Include="..\Include\internal\pycore_instruction_sequence.h" />
<ClInclude Include="..\Include\internal\pycore_interp.h" />
<ClInclude Include="..\Include\internal\pycore_intrinsics.h" />
<ClInclude Include="..\Include\internal\pycore_jit.h" />
@@ -590,6 +591,7 @@
<ClCompile Include="..\Python\initconfig.c" />
<ClCompile Include="..\Python\interpconfig.c" />
<ClCompile Include="..\Python\intrinsics.c" />
+ <ClCompile Include="..\Python\instruction_sequence.c" />
<ClCompile Include="..\Python\instrumentation.c" />
<ClCompile Include="..\Python\jit.c" />
<ClCompile Include="..\Python\legacy_tracing.c" />
diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters
index 6e0cd1754f5cff..e43970410bd378 100644
--- a/PCbuild/pythoncore.vcxproj.filters
+++ b/PCbuild/pythoncore.vcxproj.filters
@@ -663,6 +663,9 @@
<ClInclude Include="..\Include\internal\pycore_initconfig.h">
<Filter>Include\internal</Filter>
</ClInclude>
+ <ClInclude Include="..\Include\internal\pycore_instruction_sequence.h">
+ <Filter>Include\internal</Filter>
+ </ClInclude>
<ClInclude Include="..\Include\internal\pycore_interp.h">
<Filter>Include\internal</Filter>
</ClInclude>
@@ -1349,6 +1352,9 @@
<ClCompile Include="..\Python\intrinsics.c">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="..\Python\instruction_sequence.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
<ClCompile Include="..\Python\instrumentation.c">
<Filter>Source Files</Filter>
</ClCompile>
diff --git a/Python/assemble.c b/Python/assemble.c
index be3d9c1a74657c..945c8ac39f53ac 100644
--- a/Python/assemble.c
+++ b/Python/assemble.c
@@ -3,6 +3,7 @@
#include "Python.h"
#include "pycore_code.h" // write_location_entry_start()
#include "pycore_compile.h"
+#include "pycore_instruction_sequence.h"
#include "pycore_opcode_utils.h" // IS_BACKWARDS_JUMP_OPCODE
#include "pycore_opcode_metadata.h" // is_pseudo_target, _PyOpcode_Caches
#include "pycore_symtable.h" // _Py_SourceLocation
@@ -23,8 +24,8 @@
}

typedef _Py_SourceLocation location;
-typedef _PyCompile_Instruction instruction;
-typedef _PyCompile_InstructionSequence instr_sequence;
+typedef _PyInstruction instruction;
+typedef _PyInstructionSequence instr_sequence;

static inline bool
same_location(location a, location b)
@@ -132,7 +133,7 @@ assemble_emit_exception_table_item(struct assembler *a, int value, int msb)
static int
assemble_emit_exception_table_entry(struct assembler *a, int start, int end,
int handler_offset,
- _PyCompile_ExceptHandlerInfo *handler)
+ _PyExceptHandlerInfo *handler)
{
Py_ssize_t len = PyBytes_GET_SIZE(a->a_except_table);
if (a->a_except_table_off + MAX_SIZE_OF_ENTRY >= len) {
@@ -158,7 +159,7 @@ static int
assemble_exception_table(struct assembler *a, instr_sequence *instrs)
{
int ioffset = 0;
- _PyCompile_ExceptHandlerInfo handler;
+ _PyExceptHandlerInfo handler;
handler.h_label = -1;
handler.h_startdepth = -1;
handler.h_preserve_lasti = -1;
@@ -736,8 +737,7 @@ _PyAssemble_MakeCodeObject(_PyCompile_CodeUnitMetadata *umd, PyObject *const_cac
PyObject *consts, int maxdepth, instr_sequence *instrs,
int nlocalsplus, int code_flags, PyObject *filename)
{
-
- if (_PyCompile_InstructionSequence_ApplyLabelMap(instrs) < 0) {
+ if (_PyInstructionSequence_ApplyLabelMap(instrs) < 0) {
return NULL;
}
if (resolve_unconditional_jumps(instrs) < 0) {
diff --git a/Python/compile.c b/Python/compile.c
index d9312f93d0680f..1e8f97e72cdff6 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -86,7 +86,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};

@@ -94,13 +94,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(_PyCompile_InstructionSequence_UseLabel(INSTR_SEQUENCE(C), (LBL).id))
+ RETURN_IF_ERROR(_PyInstructionSequence_UseLabel(INSTR_SEQUENCE(C), (LBL).id))


/* fblockinfo tracks the current frame block.
@@ -134,8 +134,8 @@ enum {
};


-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
@@ -195,168 +195,35 @@ _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;
-}
-
-int
-_PyCompile_InstructionSequence_UseLabel(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;
-}
-
-int
-_PyCompile_InstructionSequence_ApplyLabelMap(instr_sequence *instrs)
-{
- /* Replace labels by offsets in the code */
- for (int i=0; i < instrs->s_used; i++) {
- instruction *instr = &instrs->s_instrs[i];
- if (HAS_TARGET(instr->i_opcode)) {
- assert(instr->i_oparg < instrs->s_labelmap_size);
- instr->i_oparg = instrs->s_labelmap[instr->i_oparg];
- }
- _PyCompile_ExceptHandlerInfo *hi = &instr->i_except_handler_info;
- if (hi->h_label >= 0) {
- assert(hi->h_label < instrs->s_labelmap_size);
- hi->h_label = instrs->s_labelmap[hi->h_label];
- }
- }
- /* Clear label map so it's never used again */
- PyMem_Free(instrs->s_labelmap);
- instrs->s_labelmap = NULL;
- instrs->s_labelmap_size = 0;
- return SUCCESS;
-}
-
-#define MAX_OPCODE 511
-
-int
-_PyCompile_InstructionSequence_Addop(instr_sequence *seq, int opcode, int oparg,
- location loc)
-{
- assert(0 <= opcode && opcode <= MAX_OPCODE);
- assert(IS_WITHIN_OPCODE_RANGE(opcode));
- assert(OPCODE_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]++;
- }
- }
- return SUCCESS;
-}
-
-static void
-instr_sequence_fini(instr_sequence *seq) {
- PyMem_Free(seq->s_labelmap);
- seq->s_labelmap = NULL;
-
- PyMem_Free(seq->s_instrs);
- seq->s_instrs = NULL;
-}
-
static cfg_builder*
instr_sequence_to_cfg(instr_sequence *seq) {
+ if (_PyInstructionSequence_ApplyLabelMap(seq) < 0) {
+ return NULL;
+ }
cfg_builder *g = _PyCfgBuilder_New();
if (g == NULL) {
return NULL;
}
-
- /* 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();
- goto error;
- }
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;
}
@@ -364,11 +231,9 @@ instr_sequence_to_cfg(instr_sequence *seq) {
if (_PyCfgBuilder_CheckSize(g) < 0) {
goto error;
}
- PyMem_Free(offset2lbl);
return g;
error:
_PyCfgBuilder_Free(g);
- PyMem_Free(offset2lbl);
return NULL;
}

@@ -702,7 +567,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);
+ PyInstructionSequence_Fini(&u->u_instr_sequence);
Py_CLEAR(u->u_ste);
Py_CLEAR(u->u_metadata.u_name);
Py_CLEAR(u->u_metadata.u_qualname);
@@ -952,7 +817,7 @@ codegen_addop_noarg(instr_sequence *seq, int opcode, location loc)
{
assert(!OPCODE_HAS_ARG(opcode));
assert(!IS_ASSEMBLER_OPCODE(opcode));
- return _PyCompile_InstructionSequence_Addop(seq, opcode, 0, loc);
+ return _PyInstructionSequence_Addop(seq, opcode, 0, loc);
}

static Py_ssize_t
@@ -1185,7 +1050,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 _PyCompile_InstructionSequence_Addop(seq, opcode, oparg_, loc);
+ return _PyInstructionSequence_Addop(seq, opcode, oparg_, loc);
}

static int
@@ -1195,7 +1060,7 @@ codegen_addop_j(instr_sequence *seq, location loc,
assert(IS_LABEL(target));
assert(OPCODE_HAS_JUMP(opcode) || IS_BLOCK_PUSH_OPCODE(opcode));
assert(!IS_ASSEMBLER_OPCODE(opcode));
- return _PyCompile_InstructionSequence_Addop(seq, opcode, target.id, loc);
+ return _PyInstructionSequence_Addop(seq, opcode, target.id, loc);
}

#define RETURN_IF_ERROR_IN_SCOPE(C, CALL) { \
@@ -2217,7 +2082,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));

@@ -7690,7 +7555,7 @@ optimize_and_assemble_code_unit(struct compiler_unit *u, PyObject *const_cache,

error:
Py_XDECREF(consts);
- instr_sequence_fini(&optimized_instrs);
+ PyInstructionSequence_Fini(&optimized_instrs);
_PyCfgBuilder_Free(g);
return co;
}
@@ -7763,7 +7628,7 @@ instructions_to_instr_sequence(PyObject *instructions, instr_sequence *seq)

for (int i = 0; i < num_insts; i++) {
if (is_target[i]) {
- if (_PyCompile_InstructionSequence_UseLabel(seq, i) < 0) {
+ if (_PyInstructionSequence_UseLabel(seq, i) < 0) {
goto error;
}
}
@@ -7803,7 +7668,7 @@ instructions_to_instr_sequence(PyObject *instructions, instr_sequence *seq)
if (PyErr_Occurred()) {
goto error;
}
- if (_PyCompile_InstructionSequence_Addop(seq, opcode, oparg, loc) < 0) {
+ if (_PyInstructionSequence_Addop(seq, opcode, oparg, loc) < 0) {
goto error;
}
}
@@ -7828,11 +7693,11 @@ instructions_to_cfg(PyObject *instructions)
if (g == NULL) {
goto error;
}
- instr_sequence_fini(&seq);
+ PyInstructionSequence_Fini(&seq);
return g;
error:
_PyCfgBuilder_Free(g);
- instr_sequence_fini(&seq);
+ PyInstructionSequence_Fini(&seq);
return NULL;
}

@@ -7874,11 +7739,11 @@ cfg_to_instructions(cfg_builder *g)
if (_PyCfg_ToInstructionSequence(g, &seq) < 0) {
return NULL;
}
- if (_PyCompile_InstructionSequence_ApplyLabelMap(&seq) < 0) {
+ if (_PyInstructionSequence_ApplyLabelMap(&seq) < 0) {
return NULL;
}
PyObject *res = instr_sequence_to_instructions(&seq);
- instr_sequence_fini(&seq);
+ PyInstructionSequence_Fini(&seq);
return res;
}

@@ -8048,7 +7913,7 @@ _PyCompile_CodeGen(PyObject *ast, PyObject *filename, PyCompilerFlags *pflags,
goto finally;
}

- if (_PyCompile_InstructionSequence_ApplyLabelMap(INSTR_SEQUENCE(c)) < 0) {
+ if (_PyInstructionSequence_ApplyLabelMap(INSTR_SEQUENCE(c)) < 0) {
return NULL;
}

@@ -8138,7 +8003,7 @@ _PyCompile_Assemble(_PyCompile_CodeUnitMetadata *umd, PyObject *filename,
error:
Py_DECREF(const_cache);
_PyCfgBuilder_Free(g);
- instr_sequence_fini(&optimized_instrs);
+ PyInstructionSequence_Fini(&optimized_instrs);
return co;
}

diff --git a/Python/flowgraph.c b/Python/flowgraph.c
index 9d98f6910cdf54..83768023a4d870 100644
--- a/Python/flowgraph.c
+++ b/Python/flowgraph.c
@@ -23,7 +23,7 @@
#define DEFAULT_BLOCK_SIZE 16

typedef _Py_SourceLocation location;
-typedef _PyCfgJumpTargetLabel jump_target_label;
+typedef _PyJumpTargetLabel jump_target_label;

typedef struct _PyCfgInstruction {
int i_opcode;
@@ -40,7 +40,7 @@ typedef struct _PyCfgBasicblock {
control flow. */
struct _PyCfgBasicblock *b_list;
/* The label of this block if it is a jump target, -1 otherwise */
- _PyCfgJumpTargetLabel b_label;
+ _PyJumpTargetLabel b_label;
/* Exception stack at start of block, used by assembler to create the exception handling table */
struct _PyCfgExceptStack *b_exceptstack;
/* pointer to an array of instructions, initially NULL */
@@ -81,7 +81,7 @@ struct _PyCfgBuilder {
/* pointer to the block currently being constructed */
struct _PyCfgBasicblock *g_curblock;
/* label for the next instruction to be placed */
- _PyCfgJumpTargetLabel g_current_label;
+ _PyJumpTargetLabel g_current_label;
};

typedef struct _PyCfgBuilder cfg_builder;
@@ -2712,7 +2712,7 @@ prepare_localsplus(_PyCompile_CodeUnitMetadata *umd, cfg_builder *g, int code_fl
}

int
-_PyCfg_ToInstructionSequence(cfg_builder *g, _PyCompile_InstructionSequence *seq)
+_PyCfg_ToInstructionSequence(cfg_builder *g, _PyInstructionSequence *seq)
{
int lbl = 0;
for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
@@ -2720,7 +2720,7 @@ _PyCfg_ToInstructionSequence(cfg_builder *g, _PyCompile_InstructionSequence *seq
lbl += 1;
}
for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
- RETURN_IF_ERROR(_PyCompile_InstructionSequence_UseLabel(seq, b->b_label.id));
+ RETURN_IF_ERROR(_PyInstructionSequence_UseLabel(seq, b->b_label.id));
for (int i = 0; i < b->b_iused; i++) {
cfg_instr *instr = &b->b_instr[i];
if (HAS_TARGET(instr->i_opcode)) {
@@ -2728,10 +2728,10 @@ _PyCfg_ToInstructionSequence(cfg_builder *g, _PyCompile_InstructionSequence *seq
instr->i_oparg = instr->i_target->b_label.id;
}
RETURN_IF_ERROR(
- _PyCompile_InstructionSequence_Addop(
+ _PyInstructionSequence_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;
+ _PyExceptHandlerInfo *hi = &seq->s_instrs[seq->s_used-1].i_except_handler_info;
if (instr->i_except != NULL) {
hi->h_label = instr->i_except->b_label.id;
hi->h_startdepth = instr->i_except->b_startdepth;
@@ -2750,7 +2750,7 @@ int
_PyCfg_OptimizedCfgToInstructionSequence(cfg_builder *g,
_PyCompile_CodeUnitMetadata *umd, int code_flags,
int *stackdepth, int *nlocalsplus,
- _PyCompile_InstructionSequence *seq)
+ _PyInstructionSequence *seq)
{
*stackdepth = calculate_stackdepth(g);
if (*stackdepth < 0) {
diff --git a/Python/instruction_sequence.c b/Python/instruction_sequence.c
new file mode 100644
index 00000000000000..597d2b73d19f30
--- /dev/null
+++ b/Python/instruction_sequence.c
@@ -0,0 +1,151 @@
+/*
+ * This file implements a data structure representing a sequence of
+ * instructions, which is used by different parts of the compilation
+ * pipeline.
+ */
+
+
+#include <stdbool.h>
+
+#include "Python.h"
+
+#include "pycore_compile.h" // _PyCompile_EnsureArrayLargeEnough
+#include "pycore_opcode_utils.h"
+#include "pycore_opcode_metadata.h" // OPCODE_HAS_ARG, etc
+
+typedef _PyInstruction instruction;
+typedef _PyInstructionSequence instr_sequence;
+typedef _Py_SourceLocation location;
+
+#define INITIAL_INSTR_SEQUENCE_SIZE 100
+#define INITIAL_INSTR_SEQUENCE_LABELS_MAP_SIZE 10
+
+#undef SUCCESS
+#undef ERROR
+#define SUCCESS 0
+#define ERROR -1
+
+#define RETURN_IF_ERROR(X) \
+ if ((X) == -1) { \
+ return ERROR; \
+ }
+
+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++;
+}
+
+_PyJumpTargetLabel
+_PyInstructionSequence_NewLabel(instr_sequence *seq)
+{
+ _PyJumpTargetLabel lbl = {++seq->s_next_free_label};
+ return lbl;
+}
+
+int
+_PyInstructionSequence_UseLabel(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;
+}
+
+int
+_PyInstructionSequence_ApplyLabelMap(instr_sequence *instrs)
+{
+ if (instrs->s_labelmap == NULL) {
+ /* Already applied - nothing to do */
+ return SUCCESS;
+ }
+ /* Replace labels by offsets in the code */
+ for (int i=0; i < instrs->s_used; i++) {
+ instruction *instr = &instrs->s_instrs[i];
+ if (HAS_TARGET(instr->i_opcode)) {
+ assert(instr->i_oparg < instrs->s_labelmap_size);
+ instr->i_oparg = instrs->s_labelmap[instr->i_oparg];
+ }
+ _PyExceptHandlerInfo *hi = &instr->i_except_handler_info;
+ if (hi->h_label >= 0) {
+ assert(hi->h_label < instrs->s_labelmap_size);
+ hi->h_label = instrs->s_labelmap[hi->h_label];
+ }
+ }
+ /* Clear label map so it's never used again */
+ PyMem_Free(instrs->s_labelmap);
+ instrs->s_labelmap = NULL;
+ instrs->s_labelmap_size = 0;
+ return SUCCESS;
+}
+
+#define MAX_OPCODE 511
+
+int
+_PyInstructionSequence_Addop(instr_sequence *seq, int opcode, int oparg,
+ location loc)
+{
+ assert(0 <= opcode && opcode <= MAX_OPCODE);
+ assert(IS_WITHIN_OPCODE_RANGE(opcode));
+ assert(OPCODE_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;
+}
+
+int
+_PyInstructionSequence_InsertInstruction(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]++;
+ }
+ }
+ return SUCCESS;
+}
+
+void
+PyInstructionSequence_Fini(instr_sequence *seq) {
+ PyMem_Free(seq->s_labelmap);
+ seq->s_labelmap = NULL;
+
+ PyMem_Free(seq->s_instrs);
+ seq->s_instrs = NULL;
+}

_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-leave@python.org
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: list-python-checkins@lists.gossamer-threads.com