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

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