21
21
* objects.
22
22
*/
23
23
24
+ #include <stdbool.h>
25
+
24
26
#include "Python.h"
25
27
#include "pycore_ast.h" // _PyAST_GetDocString()
26
28
#include "pycore_compile.h" // _PyFuture_FromAST()
@@ -7377,6 +7379,39 @@ optimize_cfg(struct compiler *c, struct assembler *a, PyObject *consts);
7377
7379
static int
7378
7380
ensure_exits_have_lineno (struct compiler * c );
7379
7381
7382
+ static int *
7383
+ build_cellfixedoffsets (struct compiler * c )
7384
+ {
7385
+ int nlocals = (int )PyDict_GET_SIZE (c -> u -> u_varnames );
7386
+ int ncellvars = (int )PyDict_GET_SIZE (c -> u -> u_cellvars );
7387
+ int nfreevars = (int )PyDict_GET_SIZE (c -> u -> u_freevars );
7388
+
7389
+ int noffsets = ncellvars + nfreevars ;
7390
+ int * fixed = PyMem_New (int , noffsets );
7391
+ if (fixed == NULL ) {
7392
+ PyErr_NoMemory ();
7393
+ return NULL ;
7394
+ }
7395
+ for (int i = 0 ; i < noffsets ; i ++ ) {
7396
+ fixed [i ] = nlocals + i ;
7397
+ }
7398
+
7399
+ PyObject * varname , * cellindex ;
7400
+ Py_ssize_t pos = 0 ;
7401
+ while (PyDict_Next (c -> u -> u_cellvars , & pos , & varname , & cellindex )) {
7402
+ PyObject * varindex = PyDict_GetItem (c -> u -> u_varnames , varname );
7403
+ if (varindex != NULL ) {
7404
+ assert (PyLong_AS_LONG (cellindex ) < INT_MAX );
7405
+ assert (PyLong_AS_LONG (varindex ) < INT_MAX );
7406
+ int oldindex = (int )PyLong_AS_LONG (cellindex );
7407
+ int argoffset = (int )PyLong_AS_LONG (varindex );
7408
+ fixed [oldindex ] = argoffset ;
7409
+ }
7410
+ }
7411
+
7412
+ return fixed ;
7413
+ }
7414
+
7380
7415
static inline int
7381
7416
insert_instruction (basicblock * block , int pos , struct instr * instr ) {
7382
7417
if (compiler_next_instr (block ) < 0 ) {
@@ -7390,29 +7425,48 @@ insert_instruction(basicblock *block, int pos, struct instr *instr) {
7390
7425
}
7391
7426
7392
7427
static int
7393
- insert_prefix_instructions (struct compiler * c , basicblock * entryblock ) {
7428
+ insert_prefix_instructions (struct compiler * c , basicblock * entryblock ,
7429
+ int * fixed )
7430
+ {
7394
7431
7395
7432
int flags = compute_code_flags (c );
7396
7433
if (flags < 0 ) {
7397
7434
return -1 ;
7398
7435
}
7399
7436
7400
7437
/* Set up cells for any variable that escapes, to be put in a closure. */
7401
- PyObject * k , * v ;
7402
- Py_ssize_t pos = 0 ;
7403
- while (PyDict_Next (c -> u -> u_cellvars , & pos , & k , & v )) {
7404
- assert (PyLong_AS_LONG (v ) < INT_MAX );
7405
- int cellindex = (int )PyLong_AS_LONG (v );
7406
- struct instr make_cell = {
7407
- .i_opcode = MAKE_CELL ,
7408
- // This will get fixed in offset_derefs().
7409
- .i_oparg = cellindex ,
7410
- .i_lineno = -1 ,
7411
- .i_target = NULL ,
7412
- };
7413
- if (insert_instruction (entryblock , (int )(pos - 1 ), & make_cell ) < 0 ) {
7438
+ const int ncellvars = (int )PyDict_GET_SIZE (c -> u -> u_cellvars );
7439
+ if (ncellvars ) {
7440
+ // c->u->u_cellvars has the cells out of order so we sort them
7441
+ // before adding the MAKE_CELL instructions. Note that we
7442
+ // adjust for arg cells, which come first.
7443
+ const int nvars = ncellvars + (int )PyDict_GET_SIZE (c -> u -> u_varnames );
7444
+ int * sorted = PyMem_RawCalloc (nvars , sizeof (int ));
7445
+ if (sorted == NULL ) {
7446
+ PyErr_NoMemory ();
7414
7447
return -1 ;
7415
7448
}
7449
+ for (int i = 0 ; i < ncellvars ; i ++ ) {
7450
+ sorted [fixed [i ]] = i + 1 ;
7451
+ }
7452
+ for (int i = 0 , ncellsused = 0 ; ncellsused < ncellvars ; i ++ ) {
7453
+ int oldindex = sorted [i ] - 1 ;
7454
+ if (oldindex == -1 ) {
7455
+ continue ;
7456
+ }
7457
+ struct instr make_cell = {
7458
+ .i_opcode = MAKE_CELL ,
7459
+ // This will get fixed in offset_derefs().
7460
+ .i_oparg = oldindex ,
7461
+ .i_lineno = -1 ,
7462
+ .i_target = NULL ,
7463
+ };
7464
+ if (insert_instruction (entryblock , ncellsused , & make_cell ) < 0 ) {
7465
+ return -1 ;
7466
+ }
7467
+ ncellsused += 1 ;
7468
+ }
7469
+ PyMem_RawFree (sorted );
7416
7470
}
7417
7471
7418
7472
/* Add the generator prefix instructions. */
@@ -7471,42 +7525,16 @@ guarantee_lineno_for_exits(struct assembler *a, int firstlineno) {
7471
7525
}
7472
7526
7473
7527
static int
7474
- fix_cell_offsets (struct compiler * c , basicblock * entryblock )
7528
+ fix_cell_offsets (struct compiler * c , basicblock * entryblock , int * fixedmap )
7475
7529
{
7476
- assert (PyDict_GET_SIZE (c -> u -> u_varnames ) < INT_MAX );
7477
- assert (PyDict_GET_SIZE (c -> u -> u_cellvars ) < INT_MAX );
7478
- assert (PyDict_GET_SIZE (c -> u -> u_freevars ) < INT_MAX );
7479
7530
int nlocals = (int )PyDict_GET_SIZE (c -> u -> u_varnames );
7480
7531
int ncellvars = (int )PyDict_GET_SIZE (c -> u -> u_cellvars );
7481
7532
int nfreevars = (int )PyDict_GET_SIZE (c -> u -> u_freevars );
7482
- assert (INT_MAX - nlocals - ncellvars - nfreevars > 0 );
7483
- int nlocalsplus = nlocals + ncellvars + nfreevars ;
7533
+ int noffsets = ncellvars + nfreevars ;
7484
7534
7485
- int maxoldoffset = ncellvars + nfreevars ;
7486
- int * fixedmap = PyMem_New (int , maxoldoffset + 1 );
7487
- if (fixedmap == NULL ) {
7488
- PyErr_NoMemory ();
7489
- return -1 ;
7490
- }
7491
- for (int i = 0 ; i < maxoldoffset ; i ++ ) {
7492
- fixedmap [i ] = nlocals + i ;
7493
- }
7494
-
7495
- // First map cell vars to args.
7496
- PyObject * varname , * cellindex ;
7497
- Py_ssize_t pos = 0 ;
7498
- while (PyDict_Next (c -> u -> u_cellvars , & pos , & varname , & cellindex )) {
7499
- PyObject * varindex = PyDict_GetItem (c -> u -> u_varnames , varname );
7500
- if (varindex != NULL ) {
7501
- assert (PyLong_AS_LONG (cellindex ) < INT_MAX );
7502
- assert (PyLong_AS_LONG (varindex ) < INT_MAX );
7503
- int oldindex = (int )PyLong_AS_LONG (cellindex );
7504
- int argoffset = (int )PyLong_AS_LONG (varindex );
7505
- fixedmap [oldindex ] = argoffset ;
7506
- }
7507
- }
7535
+ // First deal with duplicates (arg cells).
7508
7536
int numdropped = 0 ;
7509
- for (int i = 0 ; i < maxoldoffset ; i ++ ) {
7537
+ for (int i = 0 ; i < noffsets ; i ++ ) {
7510
7538
if (fixedmap [i ] == i + nlocals ) {
7511
7539
fixedmap [i ] -= numdropped ;
7512
7540
}
@@ -7516,7 +7544,7 @@ fix_cell_offsets(struct compiler *c, basicblock *entryblock)
7516
7544
}
7517
7545
}
7518
7546
7519
- // Then update offsets, either relative to locals or by cell2var .
7547
+ // Then update offsets, either relative to locals or by cell2arg .
7520
7548
for (basicblock * b = entryblock ; b != NULL ; b = b -> b_next ) {
7521
7549
for (int i = 0 ; i < b -> b_iused ; i ++ ) {
7522
7550
struct instr * inst = & b -> b_instr [i ];
@@ -7530,13 +7558,15 @@ fix_cell_offsets(struct compiler *c, basicblock *entryblock)
7530
7558
case STORE_DEREF :
7531
7559
case DELETE_DEREF :
7532
7560
case LOAD_CLASSDEREF :
7561
+ assert (oldoffset >= 0 );
7562
+ assert (oldoffset < noffsets );
7563
+ assert (fixedmap [oldoffset ] >= 0 );
7533
7564
inst -> i_oparg = fixedmap [oldoffset ];
7534
7565
}
7535
7566
}
7536
7567
}
7537
7568
7538
- PyMem_Free (fixedmap );
7539
- return nlocalsplus - numdropped ;
7569
+ return numdropped ;
7540
7570
}
7541
7571
7542
7572
static PyCodeObject *
@@ -7577,8 +7607,22 @@ assemble(struct compiler *c, int addNone)
7577
7607
}
7578
7608
assert (entryblock != NULL );
7579
7609
7610
+ assert (PyDict_GET_SIZE (c -> u -> u_varnames ) < INT_MAX );
7611
+ assert (PyDict_GET_SIZE (c -> u -> u_cellvars ) < INT_MAX );
7612
+ assert (PyDict_GET_SIZE (c -> u -> u_freevars ) < INT_MAX );
7613
+ int nlocals = (int )PyDict_GET_SIZE (c -> u -> u_varnames );
7614
+ int ncellvars = (int )PyDict_GET_SIZE (c -> u -> u_cellvars );
7615
+ int nfreevars = (int )PyDict_GET_SIZE (c -> u -> u_freevars );
7616
+ assert (INT_MAX - nlocals - ncellvars > 0 );
7617
+ assert (INT_MAX - nlocals - ncellvars - nfreevars > 0 );
7618
+ int nlocalsplus = nlocals + ncellvars + nfreevars ;
7619
+ int * cellfixedoffsets = build_cellfixedoffsets (c );
7620
+ if (cellfixedoffsets == NULL ) {
7621
+ goto error ;
7622
+ }
7623
+
7580
7624
// This must be called before fix_cell_offsets().
7581
- if (insert_prefix_instructions (c , entryblock )) {
7625
+ if (insert_prefix_instructions (c , entryblock , cellfixedoffsets )) {
7582
7626
goto error ;
7583
7627
}
7584
7628
@@ -7595,10 +7639,13 @@ assemble(struct compiler *c, int addNone)
7595
7639
a .a_entry = entryblock ;
7596
7640
a .a_nblocks = nblocks ;
7597
7641
7598
- int nlocalsplus = fix_cell_offsets (c , entryblock );
7599
- if (nlocalsplus < 0 ) {
7642
+ int numdropped = fix_cell_offsets (c , entryblock , cellfixedoffsets );
7643
+ PyMem_Free (cellfixedoffsets ); // At this point we're done with it.
7644
+ cellfixedoffsets = NULL ;
7645
+ if (numdropped < 0 ) {
7600
7646
goto error ;
7601
7647
}
7648
+ nlocalsplus -= numdropped ;
7602
7649
7603
7650
consts = consts_dict_keys_inorder (c -> u -> u_consts );
7604
7651
if (consts == NULL ) {
@@ -7639,10 +7686,10 @@ assemble(struct compiler *c, int addNone)
7639
7686
}
7640
7687
7641
7688
if (!assemble_exception_table (& a )) {
7642
- return 0 ;
7689
+ goto error ;
7643
7690
}
7644
7691
if (!assemble_line_range (& a )) {
7645
- return 0 ;
7692
+ goto error ;
7646
7693
}
7647
7694
7648
7695
if (_PyBytes_Resize (& a .a_lnotab , a .a_lnotab_off ) < 0 ) {
@@ -7667,6 +7714,9 @@ assemble(struct compiler *c, int addNone)
7667
7714
error :
7668
7715
Py_XDECREF (consts );
7669
7716
assemble_free (& a );
7717
+ if (cellfixedoffsets != NULL ) {
7718
+ PyMem_Free (cellfixedoffsets );
7719
+ }
7670
7720
return co ;
7671
7721
}
7672
7722
0 commit comments