summaryrefslogtreecommitdiffstats
path: root/Python
diff options
context:
space:
mode:
authorIrit Katriel <1055913+iritkatriel@users.noreply.github.com>2024-04-17 15:42:04 (GMT)
committerGitHub <noreply@github.com>2024-04-17 15:42:04 (GMT)
commitc179c0e6cbb4d1e981fffd43f207f5b1aa5388e5 (patch)
tree4600115b3e61e7404b550d81a23a235d31c183fb /Python
parentae8dfd2761e4a45afe0adada0f91f371dd121bb8 (diff)
downloadcpython-c179c0e6cbb4d1e981fffd43f207f5b1aa5388e5.zip
cpython-c179c0e6cbb4d1e981fffd43f207f5b1aa5388e5.tar.gz
cpython-c179c0e6cbb4d1e981fffd43f207f5b1aa5388e5.tar.bz2
gh-117680: make _PyInstructionSequence a PyObject and use it in tests (#117629)
Diffstat (limited to 'Python')
-rw-r--r--Python/clinic/instruction_sequence.c.h304
-rw-r--r--Python/compile.c198
-rw-r--r--Python/instruction_sequence.c300
3 files changed, 638 insertions, 164 deletions
diff --git a/Python/clinic/instruction_sequence.c.h b/Python/clinic/instruction_sequence.c.h
new file mode 100644
index 0000000..66c2cca
--- /dev/null
+++ b/Python/clinic/instruction_sequence.c.h
@@ -0,0 +1,304 @@
+/*[clinic input]
+preserve
+[clinic start generated code]*/
+
+#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+# include "pycore_gc.h" // PyGC_Head
+# include "pycore_runtime.h" // _Py_ID()
+#endif
+#include "pycore_modsupport.h" // _PyArg_NoKeywords()
+
+PyDoc_STRVAR(inst_seq_new__doc__,
+"InstructionSequenceType()\n"
+"--\n"
+"\n"
+"Create a new InstructionSequence object.");
+
+static PyObject *
+inst_seq_new_impl(PyTypeObject *type);
+
+static PyObject *
+inst_seq_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+{
+ PyObject *return_value = NULL;
+ PyTypeObject *base_tp = &_PyInstructionSequence_Type;
+
+ if ((type == base_tp || type->tp_init == base_tp->tp_init) &&
+ !_PyArg_NoPositional("InstructionSequenceType", args)) {
+ goto exit;
+ }
+ if ((type == base_tp || type->tp_init == base_tp->tp_init) &&
+ !_PyArg_NoKeywords("InstructionSequenceType", kwargs)) {
+ goto exit;
+ }
+ return_value = inst_seq_new_impl(type);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(InstructionSequenceType_use_label__doc__,
+"use_label($self, /, label)\n"
+"--\n"
+"\n"
+"Place label at current location.");
+
+#define INSTRUCTIONSEQUENCETYPE_USE_LABEL_METHODDEF \
+ {"use_label", _PyCFunction_CAST(InstructionSequenceType_use_label), METH_FASTCALL|METH_KEYWORDS, InstructionSequenceType_use_label__doc__},
+
+static PyObject *
+InstructionSequenceType_use_label_impl(_PyInstructionSequence *self,
+ int label);
+
+static PyObject *
+InstructionSequenceType_use_label(_PyInstructionSequence *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+{
+ PyObject *return_value = NULL;
+ #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+
+ #define NUM_KEYWORDS 1
+ static struct {
+ PyGC_Head _this_is_not_used;
+ PyObject_VAR_HEAD
+ PyObject *ob_item[NUM_KEYWORDS];
+ } _kwtuple = {
+ .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
+ .ob_item = { &_Py_ID(label), },
+ };
+ #undef NUM_KEYWORDS
+ #define KWTUPLE (&_kwtuple.ob_base.ob_base)
+
+ #else // !Py_BUILD_CORE
+ # define KWTUPLE NULL
+ #endif // !Py_BUILD_CORE
+
+ static const char * const _keywords[] = {"label", NULL};
+ static _PyArg_Parser _parser = {
+ .keywords = _keywords,
+ .fname = "use_label",
+ .kwtuple = KWTUPLE,
+ };
+ #undef KWTUPLE
+ PyObject *argsbuf[1];
+ int label;
+
+ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf);
+ if (!args) {
+ goto exit;
+ }
+ label = PyLong_AsInt(args[0]);
+ if (label == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ return_value = InstructionSequenceType_use_label_impl(self, label);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(InstructionSequenceType_addop__doc__,
+"addop($self, /, opcode, oparg, lineno, col_offset, end_lineno,\n"
+" end_col_offset)\n"
+"--\n"
+"\n"
+"Append an instruction.");
+
+#define INSTRUCTIONSEQUENCETYPE_ADDOP_METHODDEF \
+ {"addop", _PyCFunction_CAST(InstructionSequenceType_addop), METH_FASTCALL|METH_KEYWORDS, InstructionSequenceType_addop__doc__},
+
+static PyObject *
+InstructionSequenceType_addop_impl(_PyInstructionSequence *self, int opcode,
+ int oparg, int lineno, int col_offset,
+ int end_lineno, int end_col_offset);
+
+static PyObject *
+InstructionSequenceType_addop(_PyInstructionSequence *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+{
+ PyObject *return_value = NULL;
+ #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+
+ #define NUM_KEYWORDS 6
+ static struct {
+ PyGC_Head _this_is_not_used;
+ PyObject_VAR_HEAD
+ PyObject *ob_item[NUM_KEYWORDS];
+ } _kwtuple = {
+ .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
+ .ob_item = { &_Py_ID(opcode), &_Py_ID(oparg), &_Py_ID(lineno), &_Py_ID(col_offset), &_Py_ID(end_lineno), &_Py_ID(end_col_offset), },
+ };
+ #undef NUM_KEYWORDS
+ #define KWTUPLE (&_kwtuple.ob_base.ob_base)
+
+ #else // !Py_BUILD_CORE
+ # define KWTUPLE NULL
+ #endif // !Py_BUILD_CORE
+
+ static const char * const _keywords[] = {"opcode", "oparg", "lineno", "col_offset", "end_lineno", "end_col_offset", NULL};
+ static _PyArg_Parser _parser = {
+ .keywords = _keywords,
+ .fname = "addop",
+ .kwtuple = KWTUPLE,
+ };
+ #undef KWTUPLE
+ PyObject *argsbuf[6];
+ int opcode;
+ int oparg;
+ int lineno;
+ int col_offset;
+ int end_lineno;
+ int end_col_offset;
+
+ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 6, 6, 0, argsbuf);
+ if (!args) {
+ goto exit;
+ }
+ opcode = PyLong_AsInt(args[0]);
+ if (opcode == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ oparg = PyLong_AsInt(args[1]);
+ if (oparg == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ lineno = PyLong_AsInt(args[2]);
+ if (lineno == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ col_offset = PyLong_AsInt(args[3]);
+ if (col_offset == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ end_lineno = PyLong_AsInt(args[4]);
+ if (end_lineno == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ end_col_offset = PyLong_AsInt(args[5]);
+ if (end_col_offset == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ return_value = InstructionSequenceType_addop_impl(self, opcode, oparg, lineno, col_offset, end_lineno, end_col_offset);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(InstructionSequenceType_new_label__doc__,
+"new_label($self, /)\n"
+"--\n"
+"\n"
+"Return a new label.");
+
+#define INSTRUCTIONSEQUENCETYPE_NEW_LABEL_METHODDEF \
+ {"new_label", (PyCFunction)InstructionSequenceType_new_label, METH_NOARGS, InstructionSequenceType_new_label__doc__},
+
+static int
+InstructionSequenceType_new_label_impl(_PyInstructionSequence *self);
+
+static PyObject *
+InstructionSequenceType_new_label(_PyInstructionSequence *self, PyObject *Py_UNUSED(ignored))
+{
+ PyObject *return_value = NULL;
+ int _return_value;
+
+ _return_value = InstructionSequenceType_new_label_impl(self);
+ if ((_return_value == -1) && PyErr_Occurred()) {
+ goto exit;
+ }
+ return_value = PyLong_FromLong((long)_return_value);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(InstructionSequenceType_add_nested__doc__,
+"add_nested($self, /, nested)\n"
+"--\n"
+"\n"
+"Add a nested sequence.");
+
+#define INSTRUCTIONSEQUENCETYPE_ADD_NESTED_METHODDEF \
+ {"add_nested", _PyCFunction_CAST(InstructionSequenceType_add_nested), METH_FASTCALL|METH_KEYWORDS, InstructionSequenceType_add_nested__doc__},
+
+static PyObject *
+InstructionSequenceType_add_nested_impl(_PyInstructionSequence *self,
+ PyObject *nested);
+
+static PyObject *
+InstructionSequenceType_add_nested(_PyInstructionSequence *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+{
+ PyObject *return_value = NULL;
+ #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+
+ #define NUM_KEYWORDS 1
+ static struct {
+ PyGC_Head _this_is_not_used;
+ PyObject_VAR_HEAD
+ PyObject *ob_item[NUM_KEYWORDS];
+ } _kwtuple = {
+ .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
+ .ob_item = { &_Py_ID(nested), },
+ };
+ #undef NUM_KEYWORDS
+ #define KWTUPLE (&_kwtuple.ob_base.ob_base)
+
+ #else // !Py_BUILD_CORE
+ # define KWTUPLE NULL
+ #endif // !Py_BUILD_CORE
+
+ static const char * const _keywords[] = {"nested", NULL};
+ static _PyArg_Parser _parser = {
+ .keywords = _keywords,
+ .fname = "add_nested",
+ .kwtuple = KWTUPLE,
+ };
+ #undef KWTUPLE
+ PyObject *argsbuf[1];
+ PyObject *nested;
+
+ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf);
+ if (!args) {
+ goto exit;
+ }
+ nested = args[0];
+ return_value = InstructionSequenceType_add_nested_impl(self, nested);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(InstructionSequenceType_get_nested__doc__,
+"get_nested($self, /)\n"
+"--\n"
+"\n"
+"Add a nested sequence.");
+
+#define INSTRUCTIONSEQUENCETYPE_GET_NESTED_METHODDEF \
+ {"get_nested", (PyCFunction)InstructionSequenceType_get_nested, METH_NOARGS, InstructionSequenceType_get_nested__doc__},
+
+static PyObject *
+InstructionSequenceType_get_nested_impl(_PyInstructionSequence *self);
+
+static PyObject *
+InstructionSequenceType_get_nested(_PyInstructionSequence *self, PyObject *Py_UNUSED(ignored))
+{
+ return InstructionSequenceType_get_nested_impl(self);
+}
+
+PyDoc_STRVAR(InstructionSequenceType_get_instructions__doc__,
+"get_instructions($self, /)\n"
+"--\n"
+"\n"
+"Return the instructions as a list of tuples or labels.");
+
+#define INSTRUCTIONSEQUENCETYPE_GET_INSTRUCTIONS_METHODDEF \
+ {"get_instructions", (PyCFunction)InstructionSequenceType_get_instructions, METH_NOARGS, InstructionSequenceType_get_instructions__doc__},
+
+static PyObject *
+InstructionSequenceType_get_instructions_impl(_PyInstructionSequence *self);
+
+static PyObject *
+InstructionSequenceType_get_instructions(_PyInstructionSequence *self, PyObject *Py_UNUSED(ignored))
+{
+ return InstructionSequenceType_get_instructions_impl(self);
+}
+/*[clinic end generated code: output=8809d7aa11d9b2bb input=a9049054013a1b77]*/
diff --git a/Python/compile.c b/Python/compile.c
index 1e8f97e..3d856b7 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -32,6 +32,7 @@
#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_pystate.h" // _Py_GetConfig()
@@ -248,7 +249,7 @@ struct compiler_unit {
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;
@@ -281,12 +282,12 @@ 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 */
};
-#define INSTR_SEQUENCE(C) (&((C)->u->u_instr_sequence))
+#define INSTR_SEQUENCE(C) ((C)->u->u_instr_sequence)
typedef struct {
@@ -567,7 +568,7 @@ dictbytype(PyObject *src, int scope_type, int flag, Py_ssize_t offset)
static void
compiler_unit_free(struct compiler_unit *u)
{
- PyInstructionSequence_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);
@@ -976,7 +977,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
@@ -987,7 +988,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
@@ -1033,7 +1034,7 @@ compiler_addop_name(struct compiler_unit *u, location loc,
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 */
@@ -1252,6 +1253,8 @@ compiler_enter_scope(struct compiler *c, identifier name,
u->u_static_attributes = NULL;
}
+ u->u_instr_sequence = (instr_sequence*)_PyInstructionSequence_New();
+
/* Push the old compiler_unit on the stack. */
if (c->u) {
PyObject *capsule = PyCapsule_New(c->u, CAPSULE_NAME, NULL);
@@ -7526,7 +7529,7 @@ optimize_and_assemble_code_unit(struct compiler_unit *u, PyObject *const_cache,
if (consts == NULL) {
goto error;
}
- g = instr_sequence_to_cfg(&u->u_instr_sequence);
+ g = instr_sequence_to_cfg(u->u_instr_sequence);
if (g == NULL) {
goto error;
}
@@ -7593,160 +7596,25 @@ optimize_and_assemble(struct compiler *c, int addNone)
* 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 (_PyInstructionSequence_UseLabel(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 (OPCODE_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()) {
- goto error;
- }
- if (_PyInstructionSequence_Addop(seq, opcode, oparg, loc) < 0) {
- goto error;
- }
- }
- PyMem_Free(is_target);
- return SUCCESS;
-error:
- PyMem_Free(is_target);
- return ERROR;
-}
-
-static cfg_builder*
-instructions_to_cfg(PyObject *instructions)
-{
- cfg_builder *g = NULL;
- instr_sequence seq;
- memset(&seq, 0, sizeof(instr_sequence));
-
- if (instructions_to_instr_sequence(instructions, &seq) < 0) {
- goto error;
- }
- g = instr_sequence_to_cfg(&seq);
- if (g == NULL) {
- goto error;
- }
- PyInstructionSequence_Fini(&seq);
- return g;
-error:
- _PyCfgBuilder_Free(g);
- PyInstructionSequence_Fini(&seq);
- return NULL;
-}
static PyObject *
-instr_sequence_to_instructions(instr_sequence *seq)
+cfg_to_instruction_sequence(cfg_builder *g)
{
- PyObject *instructions = PyList_New(0);
- if (instructions == NULL) {
- return NULL;
- }
- for (int i = 0; i < seq->s_used; i++) {
- instruction *instr = &seq->s_instrs[i];
- location loc = instr->i_loc;
- PyObject *inst_tuple = Py_BuildValue(
- "(iiiiii)", instr->i_opcode, instr->i_oparg,
- loc.lineno, loc.end_lineno,
- loc.col_offset, loc.end_col_offset);
- if (inst_tuple == NULL) {
+ instr_sequence *seq = (instr_sequence *)_PyInstructionSequence_New();
+ if (seq != NULL) {
+ if (_PyCfg_ToInstructionSequence(g, seq) < 0) {
goto error;
}
-
- int res = PyList_Append(instructions, inst_tuple);
- Py_DECREF(inst_tuple);
- if (res != 0) {
+ if (_PyInstructionSequence_ApplyLabelMap(seq) < 0) {
goto error;
}
}
- return instructions;
+ return (PyObject*)seq;
error:
- Py_XDECREF(instructions);
+ PyInstructionSequence_Fini(seq);
return NULL;
}
-static PyObject *
-cfg_to_instructions(cfg_builder *g)
-{
- instr_sequence seq;
- memset(&seq, 0, sizeof(seq));
- if (_PyCfg_ToInstructionSequence(g, &seq) < 0) {
- return NULL;
- }
- if (_PyInstructionSequence_ApplyLabelMap(&seq) < 0) {
- return NULL;
- }
- PyObject *res = instr_sequence_to_instructions(&seq);
- PyInstructionSequence_Fini(&seq);
- return res;
-}
-
// C implementation of inspect.cleandoc()
//
// Difference from inspect.cleandoc():
@@ -7916,13 +7784,8 @@ _PyCompile_CodeGen(PyObject *ast, PyObject *filename, PyCompilerFlags *pflags,
if (_PyInstructionSequence_ApplyLabelMap(INSTR_SEQUENCE(c)) < 0) {
return NULL;
}
-
- PyObject *insts = instr_sequence_to_instructions(INSTR_SEQUENCE(c));
- if (insts == NULL) {
- goto finally;
- }
- 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);
@@ -7933,16 +7796,19 @@ finally:
}
PyObject *
-_PyCompile_OptimizeCfg(PyObject *instructions, PyObject *consts, int nlocals)
+_PyCompile_OptimizeCfg(PyObject *seq, PyObject *consts, int nlocals)
{
- cfg_builder *g = NULL;
- 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;
}
- g = instructions_to_cfg(instructions);
+ PyObject *res = NULL;
+ cfg_builder *g = instr_sequence_to_cfg((instr_sequence*)seq);
if (g == NULL) {
goto error;
}
@@ -7951,7 +7817,7 @@ _PyCompile_OptimizeCfg(PyObject *instructions, PyObject *consts, int nlocals)
nparams, firstlineno) < 0) {
goto error;
}
- res = cfg_to_instructions(g);
+ res = cfg_to_instruction_sequence(g);
error:
Py_DECREF(const_cache);
_PyCfgBuilder_Free(g);
@@ -7962,8 +7828,12 @@ 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;
@@ -7974,7 +7844,7 @@ _PyCompile_Assemble(_PyCompile_CodeUnitMetadata *umd, PyObject *filename,
return NULL;
}
- g = instructions_to_cfg(instructions);
+ g = instr_sequence_to_cfg((instr_sequence*)seq);
if (g == NULL) {
goto error;
}
diff --git a/Python/instruction_sequence.c b/Python/instruction_sequence.c
index 597d2b7..d843d5f 100644
--- a/Python/instruction_sequence.c
+++ b/Python/instruction_sequence.c
@@ -141,6 +141,21 @@ _PyInstructionSequence_InsertInstruction(instr_sequence *seq, int pos,
return SUCCESS;
}
+int
+_PyInstructionSequence_AddNested(instr_sequence *seq, instr_sequence *nested)
+{
+ if (seq->s_nested == NULL) {
+ seq->s_nested = PyList_New(0);
+ if (seq->s_nested == NULL) {
+ return ERROR;
+ }
+ }
+ if (PyList_Append(seq->s_nested, (PyObject*)nested) < 0) {
+ return ERROR;
+ }
+ return SUCCESS;
+}
+
void
PyInstructionSequence_Fini(instr_sequence *seq) {
PyMem_Free(seq->s_labelmap);
@@ -149,3 +164,288 @@ PyInstructionSequence_Fini(instr_sequence *seq) {
PyMem_Free(seq->s_instrs);
seq->s_instrs = NULL;
}
+
+/*[clinic input]
+class InstructionSequenceType "_PyInstructionSequence *" "&_PyInstructionSequence_Type"
+[clinic start generated code]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=589963e07480390f]*/
+
+#include "clinic/instruction_sequence.c.h"
+
+static _PyInstructionSequence*
+inst_seq_create(void)
+{
+ _PyInstructionSequence *seq;
+ seq = PyObject_GC_New(_PyInstructionSequence, &_PyInstructionSequence_Type);
+ if (seq == NULL) {
+ return NULL;
+ }
+ seq->s_instrs = NULL;
+ seq->s_allocated = 0;
+ seq->s_used = 0;
+ seq->s_next_free_label = 0;
+ seq->s_labelmap = NULL;
+ seq->s_labelmap_size = 0;
+ seq->s_nested = NULL;
+
+ PyObject_GC_Track(seq);
+ return seq;
+}
+
+PyObject*
+_PyInstructionSequence_New(void)
+{
+ _PyInstructionSequence *seq = inst_seq_create();
+ if (seq == NULL) {
+ return NULL;
+ }
+ return (PyObject*)seq;
+}
+
+/*[clinic input]
+@classmethod
+InstructionSequenceType.__new__ as inst_seq_new
+
+Create a new InstructionSequence object.
+[clinic start generated code]*/
+
+static PyObject *
+inst_seq_new_impl(PyTypeObject *type)
+/*[clinic end generated code: output=98881de92c8876f6 input=b393150146849c74]*/
+{
+ return (PyObject*)inst_seq_create();
+}
+
+/*[clinic input]
+InstructionSequenceType.use_label
+
+ label: int
+
+Place label at current location.
+[clinic start generated code]*/
+
+static PyObject *
+InstructionSequenceType_use_label_impl(_PyInstructionSequence *self,
+ int label)
+/*[clinic end generated code: output=4c06bbacb2854755 input=da55f49bb91841f3]*/
+
+{
+ if (_PyInstructionSequence_UseLabel(self, label) < 0) {
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+/*[clinic input]
+InstructionSequenceType.addop
+
+ opcode: int
+ oparg: int
+ lineno: int
+ col_offset: int
+ end_lineno: int
+ end_col_offset: int
+
+Append an instruction.
+[clinic start generated code]*/
+
+static PyObject *
+InstructionSequenceType_addop_impl(_PyInstructionSequence *self, int opcode,
+ int oparg, int lineno, int col_offset,
+ int end_lineno, int end_col_offset)
+/*[clinic end generated code: output=af0cc22c048dfbf3 input=012762ac88198713]*/
+{
+ _Py_SourceLocation loc = {lineno, col_offset, end_lineno, end_col_offset};
+ if (_PyInstructionSequence_Addop(self, opcode, oparg, loc) < 0) {
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+/*[clinic input]
+InstructionSequenceType.new_label -> int
+
+Return a new label.
+[clinic start generated code]*/
+
+static int
+InstructionSequenceType_new_label_impl(_PyInstructionSequence *self)
+/*[clinic end generated code: output=dcb0589e4f5bf4bd input=c66040b9897bc327]*/
+{
+ _PyJumpTargetLabel lbl = _PyInstructionSequence_NewLabel(self);
+ return lbl.id;
+}
+
+/*[clinic input]
+InstructionSequenceType.add_nested
+
+ nested: object
+
+Add a nested sequence.
+[clinic start generated code]*/
+
+static PyObject *
+InstructionSequenceType_add_nested_impl(_PyInstructionSequence *self,
+ PyObject *nested)
+/*[clinic end generated code: output=14540fad459f7971 input=f2c482568b3b3c0f]*/
+{
+ if (!_PyInstructionSequence_Check(nested)) {
+ PyErr_Format(PyExc_TypeError,
+ "expected an instruction sequence, not %T",
+ Py_TYPE(nested));
+ return NULL;
+ }
+ if (_PyInstructionSequence_AddNested(self, (_PyInstructionSequence*)nested) < 0) {
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+/*[clinic input]
+InstructionSequenceType.get_nested
+
+Add a nested sequence.
+[clinic start generated code]*/
+
+static PyObject *
+InstructionSequenceType_get_nested_impl(_PyInstructionSequence *self)
+/*[clinic end generated code: output=f415112c292630cb input=e429e474c57b95b4]*/
+{
+ if (self->s_nested == NULL) {
+ return PyList_New(0);
+ }
+ return Py_NewRef(self->s_nested);
+}
+
+/*[clinic input]
+InstructionSequenceType.get_instructions
+
+Return the instructions as a list of tuples or labels.
+[clinic start generated code]*/
+
+static PyObject *
+InstructionSequenceType_get_instructions_impl(_PyInstructionSequence *self)
+/*[clinic end generated code: output=23f4f3f894c301b3 input=fbadb5dadb611291]*/
+{
+ if (_PyInstructionSequence_ApplyLabelMap(self) < 0) {
+ return NULL;
+ }
+ PyObject *instructions = PyList_New(0);
+ if (instructions == NULL) {
+ return NULL;
+ }
+ for (int i = 0; i < self->s_used; i++) {
+ instruction *instr = &self->s_instrs[i];
+ location loc = instr->i_loc;
+ PyObject *inst_tuple;
+
+ if (OPCODE_HAS_ARG(instr->i_opcode)) {
+ inst_tuple = Py_BuildValue(
+ "(iiiiii)", instr->i_opcode, instr->i_oparg,
+ loc.lineno, loc.end_lineno,
+ loc.col_offset, loc.end_col_offset);
+ }
+ else {
+ inst_tuple = Py_BuildValue(
+ "(iOiiii)", instr->i_opcode, Py_None,
+ loc.lineno, loc.end_lineno,
+ loc.col_offset, loc.end_col_offset);
+ }
+ if (inst_tuple == NULL) {
+ goto error;
+ }
+
+ int res = PyList_Append(instructions, inst_tuple);
+ Py_DECREF(inst_tuple);
+ if (res != 0) {
+ goto error;
+ }
+ }
+ return instructions;
+error:
+ Py_XDECREF(instructions);
+ return NULL;
+}
+
+static PyMethodDef inst_seq_methods[] = {
+ INSTRUCTIONSEQUENCETYPE_ADDOP_METHODDEF
+ INSTRUCTIONSEQUENCETYPE_NEW_LABEL_METHODDEF
+ INSTRUCTIONSEQUENCETYPE_USE_LABEL_METHODDEF
+ INSTRUCTIONSEQUENCETYPE_ADD_NESTED_METHODDEF
+ INSTRUCTIONSEQUENCETYPE_GET_NESTED_METHODDEF
+ INSTRUCTIONSEQUENCETYPE_GET_INSTRUCTIONS_METHODDEF
+ {NULL, NULL, 0, NULL},
+};
+
+static PyMemberDef inst_seq_memberlist[] = {
+ {NULL} /* Sentinel */
+};
+
+static PyGetSetDef inst_seq_getsetters[] = {
+ {NULL} /* Sentinel */
+};
+
+static void
+inst_seq_dealloc(_PyInstructionSequence *seq)
+{
+ PyObject_GC_UnTrack(seq);
+ Py_TRASHCAN_BEGIN(seq, inst_seq_dealloc)
+ PyInstructionSequence_Fini(seq);
+ PyObject_GC_Del(seq);
+ Py_TRASHCAN_END
+}
+
+static int
+inst_seq_traverse(_PyInstructionSequence *seq, visitproc visit, void *arg)
+{
+ Py_VISIT(seq->s_nested);
+ return 0;
+}
+
+static int
+inst_seq_clear(_PyInstructionSequence *seq)
+{
+ Py_CLEAR(seq->s_nested);
+ return 0;
+}
+
+PyTypeObject _PyInstructionSequence_Type = {
+ PyVarObject_HEAD_INIT(&PyType_Type, 0)
+ "InstructionSequence",
+ sizeof(_PyInstructionSequence),
+ 0,
+ (destructor)inst_seq_dealloc, /*tp_dealloc*/
+ 0, /*tp_vectorcall_offset*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_as_async*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ PyObject_GenericGetAttr, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
+ inst_seq_new__doc__, /* tp_doc */
+ (traverseproc)inst_seq_traverse, /* tp_traverse */
+ (inquiry)inst_seq_clear, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ inst_seq_methods, /* tp_methods */
+ inst_seq_memberlist, /* tp_members */
+ inst_seq_getsetters, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ inst_seq_new, /* tp_new */
+};