Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize code generation #9

Draft
wants to merge 4 commits into
base: co_annotations
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion Objects/funcobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,30 @@ PyFunction_BindCoAnnotations(PyObject *owner, PyObject **co_annotations, PyObjec
return -1;
}

PyFunctionObject *fn = (PyFunctionObject *)PyFunction_New(co, globals);
PyObject *qualname = PyUnicode_FromFormat("%U.%s", ((PyFunctionObject*)owner)->func_qualname, "__co_annotations__");
if (qualname == NULL) {
PyErr_Clear();
}
PyObject *newcode = NULL;
if (((PyCodeObject*)co)->co_firstlineno == -1) {
// copy firstlineno from owner->func_code
PyCodeObject *old = (PyCodeObject*)co;
int firstlineno = ((PyCodeObject*)((PyFunctionObject*)owner)->func_code)->co_firstlineno;
newcode = (PyObject*)PyCode_NewWithPosOnlyArgs(
old->co_argcount, old->co_posonlyargcount, old->co_kwonlyargcount, old->co_nlocals,
old->co_stacksize, old->co_flags, old->co_code, old->co_consts, old->co_names,
old->co_varnames, old->co_freevars, old->co_cellvars, old->co_filename, old->co_name,
firstlineno, old->co_lnotab);
if (newcode == NULL) {
PyErr_Format(PyExc_RuntimeError,
"can not create code object for %R __co_annotations__",
owner);
return -1;
}
co = newcode;
}
PyFunctionObject *fn = (PyFunctionObject *)PyFunction_NewWithQualName(co, globals, qualname);
Py_CLEAR(newcode);
if (!fn) {
PyErr_Format(PyExc_ValueError,
"%R __co_annotations__ couldn't bind function object",
Expand Down
102 changes: 57 additions & 45 deletions Python/compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -765,8 +765,6 @@ compiler_exit_scope(struct compiler *c)
}


static PyObject *dot_co_annotations = NULL;

/*
* Returns >0 if we succeeded and are currently in the annotation scope.
* Returns 0 if there was an error.
Expand All @@ -788,20 +786,8 @@ compiler_enter_co_annotations_scope(struct compiler *c)
int co_annotations = c->c_future->ff_features & CO_FUTURE_CO_ANNOTATIONS;

if (co_annotations) {
if (!c->u->u_asi.basename) {
return -1;
}

if (dot_co_annotations == NULL) {
dot_co_annotations = PyUnicode_InternFromString(".__co_annotations__");
if (!dot_co_annotations)
return 0;
}

PyObject *name_dot_co_annotations = PyUnicode_Concat(c->u->u_asi.basename, dot_co_annotations);

if (!compiler_enter_scope(c,
name_dot_co_annotations,
__co_annotations__,
COMPILER_SCOPE_ANNOTATION,
c->u->u_asi.ast,
c->u->u_asi.line))
Expand Down Expand Up @@ -2353,6 +2339,9 @@ compiler_visit_annotations(struct compiler *c, arguments_ty args, expr_ty return

if (c->u->u_scope_type == COMPILER_SCOPE_ANNOTATION) {
ADDOP(c, RETURN_VALUE);
// Use -1 to share same code objects in a module.
// func.__co_annotations__ will overwrite it with func.__code__.co_firstlineno.
c->u->u_firstlineno = -1;
if (!compiler_emit_co_annotations_object(c, "function"))
return 0;
return_value = annotations_fn_flag;
Expand Down Expand Up @@ -6191,14 +6180,12 @@ compute_code_flags(struct compiler *c)
return flags;
}

// Merge *tuple* with constant cache.
// Merge *obj* with constant cache.
// Unlike merge_consts_recursive(), this function doesn't work recursively.
static int
merge_const_tuple(struct compiler *c, PyObject **tuple)
merge_const_one(struct compiler *c, PyObject **obj)
{
assert(PyTuple_CheckExact(*tuple));

PyObject *key = _PyCode_ConstantKey(*tuple);
PyObject *key = _PyCode_ConstantKey(*obj);
if (key == NULL) {
return 0;
}
Expand All @@ -6209,14 +6196,18 @@ merge_const_tuple(struct compiler *c, PyObject **tuple)
if (t == NULL) {
return 0;
}
if (t == key) { // tuple is new constant.
if (t == key) { // obj is new constant.
return 1;
}

PyObject *u = PyTuple_GET_ITEM(t, 1);
Py_INCREF(u);
Py_DECREF(*tuple);
*tuple = u;
if (PyTuple_CheckExact(t)) {
// t is still borrowed reference
t = PyTuple_GET_ITEM(t, 1);
}

Py_INCREF(t);
Py_DECREF(*obj);
*obj = t;
return 1;
}

Expand Down Expand Up @@ -6246,10 +6237,10 @@ makecode(struct compiler *c, struct assembler *a, PyObject *consts)
if (!freevars)
goto error;

if (!merge_const_tuple(c, &names) ||
!merge_const_tuple(c, &varnames) ||
!merge_const_tuple(c, &cellvars) ||
!merge_const_tuple(c, &freevars))
if (!merge_const_one(c, &names) ||
!merge_const_one(c, &varnames) ||
!merge_const_one(c, &cellvars) ||
!merge_const_one(c, &freevars))
{
goto error;
}
Expand All @@ -6266,7 +6257,7 @@ makecode(struct compiler *c, struct assembler *a, PyObject *consts)
if (consts == NULL) {
goto error;
}
if (!merge_const_tuple(c, &consts)) {
if (!merge_const_one(c, &consts)) {
Py_DECREF(consts);
goto error;
}
Expand Down Expand Up @@ -6329,7 +6320,7 @@ dump_basicblock(const basicblock *b)
#endif

static int
optimize_cfg(struct assembler *a, PyObject *consts);
optimize_cfg(struct compiler *c, struct assembler *a, PyObject *consts);

static PyCodeObject *
assemble(struct compiler *c, int addNone)
Expand Down Expand Up @@ -6373,7 +6364,7 @@ assemble(struct compiler *c, int addNone)
if (consts == NULL) {
goto error;
}
if (optimize_cfg(&a, consts)) {
if (optimize_cfg(c, &a, consts)) {
goto error;
}

Expand All @@ -6388,10 +6379,18 @@ assemble(struct compiler *c, int addNone)
goto error;
}

if (_PyBytes_Resize(&a.a_lnotab, a.a_lnotab_off) < 0)
if (_PyBytes_Resize(&a.a_lnotab, a.a_lnotab_off) < 0) {
goto error;
if (_PyBytes_Resize(&a.a_bytecode, a.a_offset * sizeof(_Py_CODEUNIT)) < 0)
}
if (!merge_const_one(c, &a.a_lnotab)) {
goto error;
}
if (_PyBytes_Resize(&a.a_bytecode, a.a_offset * sizeof(_Py_CODEUNIT)) < 0) {
goto error;
}
if (!merge_const_one(c, &a.a_bytecode)) {
goto error;
}

co = makecode(c, &a, consts);
error:
Expand All @@ -6416,7 +6415,8 @@ PyAST_Compile(mod_ty mod, const char *filename, PyCompilerFlags *flags,
Called with codestr pointing to the first LOAD_CONST.
*/
static int
fold_tuple_on_constants(struct instr *inst,
fold_tuple_on_constants(struct compiler *c,
struct instr *inst,
int n, PyObject *consts)
{
/* Pre-conditions */
Expand All @@ -6441,15 +6441,27 @@ fold_tuple_on_constants(struct instr *inst,
Py_INCREF(constant);
PyTuple_SET_ITEM(newconst, i, constant);
}
Py_ssize_t index = PyList_GET_SIZE(consts);
if ((size_t)index >= (size_t)INT_MAX - 1) {
if (merge_const_one(c, &newconst) == 0) {
Py_DECREF(newconst);
PyErr_SetString(PyExc_OverflowError, "too many constants");
return -1;
}
if (PyList_Append(consts, newconst)) {
Py_DECREF(newconst);
return -1;

Py_ssize_t index;
for (index = 0; index < PyList_GET_SIZE(consts); index++) {
if (PyList_GET_ITEM(consts, index) == newconst) {
break;
}
}
if (index == PyList_GET_SIZE(consts)) {
if ((size_t)index >= (size_t)INT_MAX - 1) {
Py_DECREF(newconst);
PyErr_SetString(PyExc_OverflowError, "too many constants");
return -1;
}
if (PyList_Append(consts, newconst)) {
Py_DECREF(newconst);
return -1;
}
}
Py_DECREF(newconst);
for (int i = 0; i < n; i++) {
Expand All @@ -6463,7 +6475,7 @@ fold_tuple_on_constants(struct instr *inst,

/* Optimization */
static int
optimize_basic_block(basicblock *bb, PyObject *consts)
optimize_basic_block(struct compiler *c, basicblock *bb, PyObject *consts)
{
assert(PyList_CheckExact(consts));
struct instr nop;
Expand Down Expand Up @@ -6525,7 +6537,7 @@ optimize_basic_block(basicblock *bb, PyObject *consts)
break;
}
if (i >= oparg) {
if (fold_tuple_on_constants(inst-oparg, oparg, consts)) {
if (fold_tuple_on_constants(c, inst-oparg, oparg, consts)) {
goto error;
}
}
Expand Down Expand Up @@ -6693,10 +6705,10 @@ mark_reachable(struct assembler *a) {
*/

static int
optimize_cfg(struct assembler *a, PyObject *consts)
optimize_cfg(struct compiler *c, struct assembler *a, PyObject *consts)
{
for (int i = 0; i < a->a_nblocks; i++) {
if (optimize_basic_block(a->a_reverse_postorder[i], consts)) {
if (optimize_basic_block(c, a->a_reverse_postorder[i], consts)) {
return -1;
}
clean_basic_block(a->a_reverse_postorder[i]);
Expand Down