bpo-33597: Reduce PyGC_Head size (GH-7043) · python/cpython@5ac9e6e (original) (raw)

`@@ -251,76 +251,88 @@ PyAPI_FUNC(PyVarObject *) _PyObject_GC_Resize(PyVarObject *, Py_ssize_t);

`

251

251

``

252

252

`/* GC information is stored BEFORE the object structure. */

`

253

253

`#ifndef Py_LIMITED_API

`

254

``

`-

typedef union _gc_head {

`

255

``

`-

struct {

`

256

``

`-

union _gc_head *gc_next;

`

257

``

`-

union _gc_head *gc_prev;

`

258

``

`-

Py_ssize_t gc_refs;

`

259

``

`-

} gc;

`

260

``

`-

double dummy; /* force worst-case alignment */

`

``

254

`+

typedef struct {

`

``

255

`+

// Pointer to next object in the list.

`

``

256

`+

// 0 means the object is not tracked

`

``

257

`+

uintptr_t _gc_next;

`

``

258

+

``

259

`+

// Pointer to previous object in the list.

`

``

260

`+

// Lowest two bits are used for flags documented later.

`

``

261

`+

uintptr_t _gc_prev;

`

261

262

`} PyGC_Head;

`

262

263

``

263

264

`extern PyGC_Head *_PyGC_generation0;

`

264

265

``

265

266

`#define _Py_AS_GC(o) ((PyGC_Head *)(o)-1)

`

266

267

``

``

268

`+

/* Bit flags for _gc_prev */

`

267

269

`/* Bit 0 is set when tp_finalize is called */

`

268

``

`-

#define _PyGC_REFS_MASK_FINALIZED (1 << 0)

`

269

``

`-

/* The (N-1) most significant bits contain the gc state / refcount */

`

270

``

`-

#define _PyGC_REFS_SHIFT (1)

`

271

``

`-

#define _PyGC_REFS_MASK (((size_t) -1) << _PyGC_REFS_SHIFT)

`

272

``

-

273

``

`-

#define _PyGCHead_REFS(g) ((g)->gc.gc_refs >> _PyGC_REFS_SHIFT)

`

274

``

`-

#define _PyGCHead_SET_REFS(g, v) do { \

`

275

``

`-

(g)->gc.gc_refs = ((g)->gc.gc_refs & ~_PyGC_REFS_MASK) \

`

276

``

`-

| (((size_t)(v)) << _PyGC_REFS_SHIFT); \

`

``

270

`+

#define _PyGC_PREV_MASK_FINALIZED (1)

`

``

271

`+

/* Bit 1 is set when the object is in generation which is GCed currently. */

`

``

272

`+

#define _PyGC_PREV_MASK_COLLECTING (2)

`

``

273

`+

/* The (N-2) most significant bits contain the real address. */

`

``

274

`+

#define _PyGC_PREV_SHIFT (2)

`

``

275

`+

#define _PyGC_PREV_MASK (((uintptr_t) -1) << _PyGC_PREV_SHIFT)

`

``

276

+

``

277

`+

// Lowest bit of _gc_next is used for flags only in GC.

`

``

278

`+

// But it is always 0 for normal code.

`

``

279

`+

#define _PyGCHead_NEXT(g) ((PyGC_Head*)(g)->_gc_next)

`

``

280

`+

#define _PyGCHead_SET_NEXT(g, p) ((g)->_gc_next = (uintptr_t)(p))

`

``

281

+

``

282

`+

// Lowest two bits of _gc_prev is used for PyGC_PREV_MASK* flags.

`

``

283

`+

#define _PyGCHead_PREV(g) ((PyGC_Head*)((g)->_gc_prev & _PyGC_PREV_MASK))

`

``

284

`+

#define _PyGCHead_SET_PREV(g, p) do { \

`

``

285

`+

assert(((uintptr_t)p & ~_PyGC_PREV_MASK) == 0); \

`

``

286

`+

(g)->_gc_prev = ((g)->_gc_prev & ~_PyGC_PREV_MASK) \

`

``

287

`+

| ((uintptr_t)(p)); \

`

277

288

` } while (0)

`

278

``

`-

#define _PyGCHead_DECREF(g) ((g)->gc.gc_refs -= 1 << _PyGC_REFS_SHIFT)

`

279

289

``

280

``

`-

#define _PyGCHead_FINALIZED(g) (((g)->gc.gc_refs & _PyGC_REFS_MASK_FINALIZED) != 0)

`

281

``

`-

#define _PyGCHead_SET_FINALIZED(g, v) do { \

`

282

``

`-

(g)->gc.gc_refs = ((g)->gc.gc_refs & ~_PyGC_REFS_MASK_FINALIZED) \

`

283

``

`-

| (v != 0); \

`

284

``

`-

} while (0)

`

``

290

`+

#define _PyGCHead_FINALIZED(g) (((g)->_gc_prev & _PyGC_PREV_MASK_FINALIZED) != 0)

`

``

291

`+

#define _PyGCHead_SET_FINALIZED(g) ((g)->_gc_prev |= _PyGC_PREV_MASK_FINALIZED)

`

285

292

``

286

293

`#define _PyGC_FINALIZED(o) _PyGCHead_FINALIZED(_Py_AS_GC(o))

`

287

``

`-

#define _PyGC_SET_FINALIZED(o, v) _PyGCHead_SET_FINALIZED(_Py_AS_GC(o), v)

`

288

``

-

289

``

`-

#define _PyGC_REFS(o) _PyGCHead_REFS(_Py_AS_GC(o))

`

290

``

-

291

``

`-

#define _PyGC_REFS_UNTRACKED (-2)

`

292

``

`-

#define _PyGC_REFS_REACHABLE (-3)

`

293

``

`-

#define _PyGC_REFS_TENTATIVELY_UNREACHABLE (-4)

`

294

``

-

295

``

`-

/* Tell the GC to track this object. NB: While the object is tracked the

`

296

``

`-

`

``

294

`+

#define _PyGC_SET_FINALIZED(o) _PyGCHead_SET_FINALIZED(_Py_AS_GC(o))

`

``

295

+

``

296

`+

/* Tell the GC to track this object.

`

``

297

`+

`

``

298

`+

`

``

299

`+

`

``

300

`+

`

``

301

`+

`

``

302

`+

`

``

303

`+

`

``

304

`+

*/

`

297

305

`#define _PyObject_GC_TRACK(o) do { \

`

298

306

` PyGC_Head *g = _Py_AS_GC(o); \

`

299

``

`-

if (_PyGCHead_REFS(g) != _PyGC_REFS_UNTRACKED) \

`

``

307

`+

if (g->_gc_next != 0) { \

`

300

308

` Py_FatalError("GC object already tracked"); \

`

301

``

`-

_PyGCHead_SET_REFS(g, _PyGC_REFS_REACHABLE); \

`

302

``

`-

g->gc.gc_next = _PyGC_generation0; \

`

303

``

`-

g->gc.gc_prev = _PyGC_generation0->gc.gc_prev; \

`

304

``

`-

g->gc.gc_prev->gc.gc_next = g; \

`

305

``

`-

_PyGC_generation0->gc.gc_prev = g; \

`

``

309

`+

} \

`

``

310

`+

assert((g->_gc_prev & _PyGC_PREV_MASK_COLLECTING) == 0); \

`

``

311

`+

PyGC_Head last = (PyGC_Head)(_PyGC_generation0->_gc_prev); \

`

``

312

`+

_PyGCHead_SET_NEXT(last, g); \

`

``

313

`+

_PyGCHead_SET_PREV(g, last); \

`

``

314

`+

_PyGCHead_SET_NEXT(g, _PyGC_generation0); \

`

``

315

`+

_PyGC_generation0->_gc_prev = (uintptr_t)g; \

`

306

316

` } while (0);

`

307

317

``

308

318

`/* Tell the GC to stop tracking this object.

`

309

``

`-

`

310

``

`-

`

``

319

`+

`

``

320

`+

`

``

321

`+

`

311

322

` */

`

312

323

`#define _PyObject_GC_UNTRACK(o) do { \

`

313

324

` PyGC_Head *g = _Py_AS_GC(o); \

`

314

``

`-

assert(_PyGCHead_REFS(g) != _PyGC_REFS_UNTRACKED); \

`

315

``

`-

_PyGCHead_SET_REFS(g, _PyGC_REFS_UNTRACKED); \

`

316

``

`-

g->gc.gc_prev->gc.gc_next = g->gc.gc_next; \

`

317

``

`-

g->gc.gc_next->gc.gc_prev = g->gc.gc_prev; \

`

318

``

`-

g->gc.gc_next = NULL; \

`

``

325

`+

PyGC_Head *prev = _PyGCHead_PREV(g); \

`

``

326

`+

PyGC_Head *next = _PyGCHead_NEXT(g); \

`

``

327

`+

assert(next != NULL); \

`

``

328

`+

_PyGCHead_SET_NEXT(prev, next); \

`

``

329

`+

_PyGCHead_SET_PREV(next, prev); \

`

``

330

`+

g->_gc_next = 0; \

`

``

331

`+

g->_gc_prev &= _PyGC_PREV_MASK_FINALIZED; \

`

319

332

` } while (0);

`

320

333

``

321

334

`/* True if the object is currently tracked by the GC. */

`

322

``

`-

#define _PyObject_GC_IS_TRACKED(o) \

`

323

``

`-

(_PyGC_REFS(o) != _PyGC_REFS_UNTRACKED)

`

``

335

`+

#define _PyObject_GC_IS_TRACKED(o) (_Py_AS_GC(o)->_gc_next != 0)

`

324

336

``

325

337

`/* True if the object may be tracked by the GC in the future, or already is.

`

326

338

` This can be useful to implement some optimizations. */

`