]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-117494: extract the Instruction Sequence data structure into a separate file ...
authorIrit Katriel <1055913+iritkatriel@users.noreply.github.com>
Thu, 4 Apr 2024 15:47:26 +0000 (16:47 +0100)
committerGitHub <noreply@github.com>
Thu, 4 Apr 2024 15:47:26 +0000 (15:47 +0000)
13 files changed:
Include/internal/pycore_compile.h
Include/internal/pycore_flowgraph.h
Include/internal/pycore_instruction_sequence.h [new file with mode: 0644]
Makefile.pre.in
Misc/NEWS.d/next/Core and Builtins/2024-04-04-13-42-59.gh-issue-117494.GPQH64.rst [new file with mode: 0644]
PCbuild/_freeze_module.vcxproj
PCbuild/_freeze_module.vcxproj.filters
PCbuild/pythoncore.vcxproj
PCbuild/pythoncore.vcxproj.filters
Python/assemble.c
Python/compile.c
Python/flowgraph.c
Python/instruction_sequence.c [new file with mode: 0644]

index eb6e5ca58f7390e9d9c3ef3e2bc35e3ffa8eac9f..3c21f83a18b52acb264ca6fa09ae602634654244 100644 (file)
@@ -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;
index 121302aacb3a8b463a79065a183e980c64d92902..819117b83114bcd5cf7d6d64fb04f5a9e07b6b40 100644 (file)
@@ -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 (file)
index 0000000..b57484f
--- /dev/null
@@ -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 */
index 84058acdcc35fce315c51474f620384a63225390..fd8678cdaf820747451606c1937e543b3176e176 100644 (file)
@@ -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 (file)
index 0000000..3b550ed
--- /dev/null
@@ -0,0 +1 @@
+Refactored the instruction sequence data structure out of compile.c into instruction_sequence.c.
index 9c82fcf021bb55a680689e452d511368a88e8ae4..9717d89b54d828bfbba15171e62203d2cc4acbbe 100644 (file)
     <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" />
index 63b033a0350b2019aeb6e31747b8c5d33e227344..9b106bea601e347ccdee747e154744b15c08ca1a 100644 (file)
     <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>
index 827c9f074de90910952ff23b4659c6547510d3cc..3a019a5fe550dbd1839e530fd0c35583161c06ba 100644 (file)
     <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" />
     <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" />
index 6e0cd1754f5cff4a5612c8cfe48397b513599393..e43970410bd378ef3d6cd6a4396aa0113404f7eb 100644 (file)
     <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>
     <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>
index be3d9c1a74657ca716ad811220fa53371ed3d7de..945c8ac39f53acd65c3a73e9adb511ece2103120 100644 (file)
@@ -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) {
index d9312f93d0680f551d75239ad4737071ad485b00..1e8f97e72cdff6da01b096b38e5dd4b7bc18e90d 100644 (file)
@@ -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;
 }
 
index 9d98f6910cdf54ebb8f6ab54a6b45609432005de..83768023a4d870e331ad1b98360f067e34c4c74e 100644 (file)
@@ -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 (file)
index 0000000..597d2b7
--- /dev/null
@@ -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;
+}