Skip to content

Commit 1ffdc1b

Browse files
Track code object local kinds for arguments.
1 parent 8a4d4f3 commit 1ffdc1b

File tree

2 files changed

+62
-17
lines changed

2 files changed

+62
-17
lines changed

Include/internal/pycore_code.h

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -177,12 +177,14 @@ typedef struct {
177177
*/
178178

179179
// Note that these all fit within a byte, as do combinations.
180-
// Later, we will use the smaller numbers to differentiate the different
181-
// kinds of locals (e.g. pos-only arg, varkwargs, local-only).
182-
#define CO_FAST_HIDDEN 0x10
183-
#define CO_FAST_LOCAL 0x20
184-
#define CO_FAST_CELL 0x40
185-
#define CO_FAST_FREE 0x80
180+
#define CO_FAST_ARG_POS (0x02) // pos-only, pos-or-kw, varargs
181+
#define CO_FAST_ARG_KW (0x04) // kw-only, pos-or-kw, varkwargs
182+
#define CO_FAST_ARG_VAR (0x08) // varargs, varkwargs
183+
#define CO_FAST_ARG (CO_FAST_ARG_POS | CO_FAST_ARG_KW | CO_FAST_ARG_VAR)
184+
#define CO_FAST_HIDDEN (0x10)
185+
#define CO_FAST_LOCAL (0x20)
186+
#define CO_FAST_CELL (0x40)
187+
#define CO_FAST_FREE (0x80)
186188

187189
typedef unsigned char _PyLocals_Kind;
188190

Python/assemble.c

Lines changed: 54 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -482,28 +482,62 @@ extern void _Py_set_localsplus_info(int, PyObject *, unsigned char,
482482

483483
static int
484484
compute_localsplus_info(_PyCompile_CodeUnitMetadata *umd, int nlocalsplus,
485-
PyObject *names, PyObject *kinds)
485+
int flags, PyObject *names, PyObject *kinds)
486486
{
487+
// Compute the arg flags.
488+
// Currently arg vars fill the first portion of the list.
489+
char *argkinds = PyMem_Calloc(nlocalsplus, sizeof(char));
490+
if (argkinds == NULL) {
491+
PyErr_NoMemory();
492+
return ERROR;
493+
}
494+
int numargvars = 0;
495+
int max = (int)umd->u_posonlyargcount;
496+
for (; numargvars < max; numargvars++) {
497+
argkinds[numargvars] = CO_FAST_ARG_POS;
498+
}
499+
max += (int)umd->u_argcount;
500+
for (; numargvars < max; numargvars++) {
501+
argkinds[numargvars] = CO_FAST_ARG_POS | CO_FAST_ARG_KW;
502+
}
503+
max += (int)umd->u_kwonlyargcount;
504+
for (; numargvars < max; numargvars++) {
505+
argkinds[numargvars] = CO_FAST_ARG_KW;
506+
}
507+
if (flags & CO_VARARGS) {
508+
argkinds[numargvars] = CO_FAST_ARG_VAR | CO_FAST_ARG_POS;
509+
numargvars += 1;
510+
}
511+
if (flags & CO_VARKEYWORDS) {
512+
argkinds[numargvars] = CO_FAST_ARG_VAR | CO_FAST_ARG_KW;
513+
numargvars += 1;
514+
}
515+
516+
// Set the locals kinds.
487517
PyObject *k, *v;
488518
Py_ssize_t pos = 0;
489519
while (PyDict_Next(umd->u_varnames, &pos, &k, &v)) {
490520
int offset = PyLong_AsInt(v);
491521
if (offset == -1 && PyErr_Occurred()) {
492-
return ERROR;
522+
goto error;
493523
}
494524
assert(offset >= 0);
495525
assert(offset < nlocalsplus);
496526

497-
// For now we do not distinguish arg kinds.
498-
_PyLocals_Kind kind = CO_FAST_LOCAL;
527+
_PyLocals_Kind kind = CO_FAST_LOCAL | argkinds[offset];
528+
499529
int has_key = PyDict_Contains(umd->u_fasthidden, k);
500-
RETURN_IF_ERROR(has_key);
530+
if (has_key < 0) {
531+
goto error;
532+
}
501533
if (has_key) {
502534
kind |= CO_FAST_HIDDEN;
503535
}
504536

505537
has_key = PyDict_Contains(umd->u_cellvars, k);
506-
RETURN_IF_ERROR(has_key);
538+
if (has_key < 0) {
539+
goto error;
540+
}
507541
if (has_key) {
508542
kind |= CO_FAST_CELL;
509543
}
@@ -517,7 +551,9 @@ compute_localsplus_info(_PyCompile_CodeUnitMetadata *umd, int nlocalsplus,
517551
pos = 0;
518552
while (PyDict_Next(umd->u_cellvars, &pos, &k, &v)) {
519553
int has_name = PyDict_Contains(umd->u_varnames, k);
520-
RETURN_IF_ERROR(has_name);
554+
if (has_name < 0) {
555+
goto error;
556+
}
521557
if (has_name) {
522558
// Skip cells that are already covered by locals.
523559
numdropped += 1;
@@ -526,7 +562,7 @@ compute_localsplus_info(_PyCompile_CodeUnitMetadata *umd, int nlocalsplus,
526562

527563
cellvar_offset = PyLong_AsInt(v);
528564
if (cellvar_offset == -1 && PyErr_Occurred()) {
529-
return ERROR;
565+
goto error;
530566
}
531567
assert(cellvar_offset >= 0);
532568
cellvar_offset += nlocals - numdropped;
@@ -538,7 +574,7 @@ compute_localsplus_info(_PyCompile_CodeUnitMetadata *umd, int nlocalsplus,
538574
while (PyDict_Next(umd->u_freevars, &pos, &k, &v)) {
539575
int offset = PyLong_AsInt(v);
540576
if (offset == -1 && PyErr_Occurred()) {
541-
return ERROR;
577+
goto error;
542578
}
543579
assert(offset >= 0);
544580
offset += nlocals - numdropped;
@@ -549,7 +585,12 @@ compute_localsplus_info(_PyCompile_CodeUnitMetadata *umd, int nlocalsplus,
549585
assert(offset > cellvar_offset);
550586
_Py_set_localsplus_info(offset, k, CO_FAST_FREE, names, kinds);
551587
}
588+
PyMem_Free(argkinds);
552589
return SUCCESS;
590+
591+
error:
592+
PyMem_Free(argkinds);
593+
return ERROR;
553594
}
554595

555596
static PyCodeObject *
@@ -594,8 +635,10 @@ makecode(_PyCompile_CodeUnitMetadata *umd, struct assembler *a, PyObject *const_
594635
if (localspluskinds == NULL) {
595636
goto error;
596637
}
597-
if (compute_localsplus_info(umd, nlocalsplus,
598-
localsplusnames, localspluskinds) == ERROR) {
638+
if (compute_localsplus_info(
639+
umd, nlocalsplus, code_flags,
640+
localsplusnames, localspluskinds) == ERROR)
641+
{
599642
goto error;
600643
}
601644

0 commit comments

Comments
 (0)