gh-117680: make _PyInstructionSequence a PyObject and use it in tests (#117629)

This commit is contained in:
Irit Katriel 2024-04-17 16:42:04 +01:00 committed by GitHub
parent ae8dfd2761
commit c179c0e6cb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 838 additions and 242 deletions

304
Python/clinic/instruction_sequence.c.h generated Normal file
View file

@ -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]*/

View file

@ -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;
}

View file

@ -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 */
};