mirror of
https://github.com/python/cpython.git
synced 2024-11-24 10:24:35 +08:00
SF bug [#467145] Python 2.2a4 build problem on HPUX 11.0.
The platform requires 8-byte alignment for doubles, but the GC header was 12 bytes and that threw off the natural alignment of the double members of a subtype of complex. The fix puts the GC header into a union with a double as the other member, to force no-looser-than double alignment of GC headers. On boxes that require 8-byte alignment for doubles, this may add pad bytes to the GC header accordingly; ditto for platforms that *prefer* 8-byte alignment for doubles. On platforms that don't care, it shouldn't change the memory layout (because the size of the old GC header is certainly greater than the size of a double on all platforms, so unioning with a double shouldn't change size or alignment on such boxes).
This commit is contained in:
parent
f3623f310e
commit
9e4ca10ce4
@ -266,10 +266,13 @@ extern DL_IMPORT(void) _PyObject_GC_UnTrack(PyObject *);
|
||||
#ifdef WITH_CYCLE_GC
|
||||
|
||||
/* GC information is stored BEFORE the object structure */
|
||||
typedef struct _gc_head {
|
||||
struct _gc_head *gc_next; /* not NULL if object is tracked */
|
||||
struct _gc_head *gc_prev;
|
||||
int gc_refs;
|
||||
typedef union _gc_head {
|
||||
struct {
|
||||
union _gc_head *gc_next; /* not NULL if object is tracked */
|
||||
union _gc_head *gc_prev;
|
||||
int gc_refs;
|
||||
} gc;
|
||||
double dummy; /* force worst-case alignment */
|
||||
} PyGC_Head;
|
||||
|
||||
extern PyGC_Head _PyGC_generation0;
|
||||
@ -278,20 +281,20 @@ extern PyGC_Head _PyGC_generation0;
|
||||
* collector it must be safe to call the ob_traverse method. */
|
||||
#define _PyObject_GC_TRACK(o) do { \
|
||||
PyGC_Head *g = (PyGC_Head *)(o)-1; \
|
||||
if (g->gc_next != NULL) \
|
||||
if (g->gc.gc_next != NULL) \
|
||||
Py_FatalError("GC object already in linked list"); \
|
||||
g->gc_next = &_PyGC_generation0; \
|
||||
g->gc_prev = _PyGC_generation0.gc_prev; \
|
||||
g->gc_prev->gc_next = g; \
|
||||
_PyGC_generation0.gc_prev = g; \
|
||||
g->gc.gc_next = &_PyGC_generation0; \
|
||||
g->gc.gc_prev = _PyGC_generation0.gc.gc_prev; \
|
||||
g->gc.gc_prev->gc.gc_next = g; \
|
||||
_PyGC_generation0.gc.gc_prev = g; \
|
||||
} while (0);
|
||||
|
||||
/* Tell the GC to stop tracking this object. */
|
||||
#define _PyObject_GC_UNTRACK(o) do { \
|
||||
PyGC_Head *g = (PyGC_Head *)(o)-1; \
|
||||
g->gc_prev->gc_next = g->gc_next; \
|
||||
g->gc_next->gc_prev = g->gc_prev; \
|
||||
g->gc_next = NULL; \
|
||||
g->gc.gc_prev->gc.gc_next = g->gc.gc_next; \
|
||||
g->gc.gc_next->gc.gc_prev = g->gc.gc_prev; \
|
||||
g->gc.gc_next = NULL; \
|
||||
} while (0);
|
||||
|
||||
#define PyObject_GC_Track(op) _PyObject_GC_Track((PyObject *)op)
|
||||
|
@ -77,39 +77,39 @@ static PyObject *gc_str;
|
||||
static void
|
||||
gc_list_init(PyGC_Head *list)
|
||||
{
|
||||
list->gc_prev = list;
|
||||
list->gc_next = list;
|
||||
list->gc.gc_prev = list;
|
||||
list->gc.gc_next = list;
|
||||
}
|
||||
|
||||
static void
|
||||
gc_list_append(PyGC_Head *node, PyGC_Head *list)
|
||||
{
|
||||
node->gc_next = list;
|
||||
node->gc_prev = list->gc_prev;
|
||||
node->gc_prev->gc_next = node;
|
||||
list->gc_prev = node;
|
||||
node->gc.gc_next = list;
|
||||
node->gc.gc_prev = list->gc.gc_prev;
|
||||
node->gc.gc_prev->gc.gc_next = node;
|
||||
list->gc.gc_prev = node;
|
||||
}
|
||||
|
||||
static void
|
||||
gc_list_remove(PyGC_Head *node)
|
||||
{
|
||||
node->gc_prev->gc_next = node->gc_next;
|
||||
node->gc_next->gc_prev = node->gc_prev;
|
||||
node->gc_next = NULL; /* object is not currently tracked */
|
||||
node->gc.gc_prev->gc.gc_next = node->gc.gc_next;
|
||||
node->gc.gc_next->gc.gc_prev = node->gc.gc_prev;
|
||||
node->gc.gc_next = NULL; /* object is not currently tracked */
|
||||
}
|
||||
|
||||
static void
|
||||
gc_list_move(PyGC_Head *from, PyGC_Head *to)
|
||||
{
|
||||
if (from->gc_next == from) {
|
||||
if (from->gc.gc_next == from) {
|
||||
/* empty from list */
|
||||
gc_list_init(to);
|
||||
}
|
||||
else {
|
||||
to->gc_next = from->gc_next;
|
||||
to->gc_next->gc_prev = to;
|
||||
to->gc_prev = from->gc_prev;
|
||||
to->gc_prev->gc_next = to;
|
||||
to->gc.gc_next = from->gc.gc_next;
|
||||
to->gc.gc_next->gc.gc_prev = to;
|
||||
to->gc.gc_prev = from->gc.gc_prev;
|
||||
to->gc.gc_prev->gc.gc_next = to;
|
||||
}
|
||||
gc_list_init(from);
|
||||
}
|
||||
@ -119,12 +119,12 @@ static void
|
||||
gc_list_merge(PyGC_Head *from, PyGC_Head *to)
|
||||
{
|
||||
PyGC_Head *tail;
|
||||
if (from->gc_next != from) {
|
||||
tail = to->gc_prev;
|
||||
tail->gc_next = from->gc_next;
|
||||
tail->gc_next->gc_prev = tail;
|
||||
to->gc_prev = from->gc_prev;
|
||||
to->gc_prev->gc_next = to;
|
||||
if (from->gc.gc_next != from) {
|
||||
tail = to->gc.gc_prev;
|
||||
tail->gc.gc_next = from->gc.gc_next;
|
||||
tail->gc.gc_next->gc.gc_prev = tail;
|
||||
to->gc.gc_prev = from->gc.gc_prev;
|
||||
to->gc.gc_prev->gc.gc_next = to;
|
||||
}
|
||||
gc_list_init(from);
|
||||
}
|
||||
@ -134,7 +134,7 @@ gc_list_size(PyGC_Head *list)
|
||||
{
|
||||
PyGC_Head *gc;
|
||||
long n = 0;
|
||||
for (gc = list->gc_next; gc != list; gc = gc->gc_next) {
|
||||
for (gc = list->gc.gc_next; gc != list; gc = gc->gc.gc_next) {
|
||||
n++;
|
||||
}
|
||||
return n;
|
||||
@ -148,9 +148,9 @@ gc_list_size(PyGC_Head *list)
|
||||
static void
|
||||
update_refs(PyGC_Head *containers)
|
||||
{
|
||||
PyGC_Head *gc = containers->gc_next;
|
||||
for (; gc != containers; gc=gc->gc_next) {
|
||||
gc->gc_refs = FROM_GC(gc)->ob_refcnt;
|
||||
PyGC_Head *gc = containers->gc.gc_next;
|
||||
for (; gc != containers; gc=gc->gc.gc_next) {
|
||||
gc->gc.gc_refs = FROM_GC(gc)->ob_refcnt;
|
||||
}
|
||||
}
|
||||
|
||||
@ -159,8 +159,8 @@ visit_decref(PyObject *op, void *data)
|
||||
{
|
||||
if (op && PyObject_IS_GC(op)) {
|
||||
PyGC_Head *gc = AS_GC(op);
|
||||
if (gc->gc_next != NULL)
|
||||
AS_GC(op)->gc_refs--;
|
||||
if (gc->gc.gc_next != NULL)
|
||||
AS_GC(op)->gc.gc_refs--;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -170,8 +170,8 @@ static void
|
||||
subtract_refs(PyGC_Head *containers)
|
||||
{
|
||||
traverseproc traverse;
|
||||
PyGC_Head *gc = containers->gc_next;
|
||||
for (; gc != containers; gc=gc->gc_next) {
|
||||
PyGC_Head *gc = containers->gc.gc_next;
|
||||
for (; gc != containers; gc=gc->gc.gc_next) {
|
||||
traverse = FROM_GC(gc)->ob_type->tp_traverse;
|
||||
(void) traverse(FROM_GC(gc),
|
||||
(visitproc)visit_decref,
|
||||
@ -184,13 +184,13 @@ static void
|
||||
move_roots(PyGC_Head *containers, PyGC_Head *roots)
|
||||
{
|
||||
PyGC_Head *next;
|
||||
PyGC_Head *gc = containers->gc_next;
|
||||
PyGC_Head *gc = containers->gc.gc_next;
|
||||
while (gc != containers) {
|
||||
next = gc->gc_next;
|
||||
if (gc->gc_refs > 0) {
|
||||
next = gc->gc.gc_next;
|
||||
if (gc->gc.gc_refs > 0) {
|
||||
gc_list_remove(gc);
|
||||
gc_list_append(gc, roots);
|
||||
gc->gc_refs = GC_MOVED;
|
||||
gc->gc.gc_refs = GC_MOVED;
|
||||
}
|
||||
gc = next;
|
||||
}
|
||||
@ -201,10 +201,10 @@ visit_move(PyObject *op, PyGC_Head *tolist)
|
||||
{
|
||||
if (PyObject_IS_GC(op)) {
|
||||
PyGC_Head *gc = AS_GC(op);
|
||||
if (gc->gc_next != NULL && gc->gc_refs != GC_MOVED) {
|
||||
if (gc->gc.gc_next != NULL && gc->gc.gc_refs != GC_MOVED) {
|
||||
gc_list_remove(gc);
|
||||
gc_list_append(gc, tolist);
|
||||
gc->gc_refs = GC_MOVED;
|
||||
gc->gc.gc_refs = GC_MOVED;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@ -215,8 +215,8 @@ static void
|
||||
move_root_reachable(PyGC_Head *reachable)
|
||||
{
|
||||
traverseproc traverse;
|
||||
PyGC_Head *gc = reachable->gc_next;
|
||||
for (; gc != reachable; gc=gc->gc_next) {
|
||||
PyGC_Head *gc = reachable->gc.gc_next;
|
||||
for (; gc != reachable; gc=gc->gc.gc_next) {
|
||||
/* careful, reachable list is growing here */
|
||||
PyObject *op = FROM_GC(gc);
|
||||
traverse = op->ob_type->tp_traverse;
|
||||
@ -231,7 +231,7 @@ static void
|
||||
move_finalizers(PyGC_Head *unreachable, PyGC_Head *finalizers)
|
||||
{
|
||||
PyGC_Head *next;
|
||||
PyGC_Head *gc = unreachable->gc_next;
|
||||
PyGC_Head *gc = unreachable->gc.gc_next;
|
||||
static PyObject *delstr = NULL;
|
||||
if (delstr == NULL) {
|
||||
delstr = PyString_InternFromString("__del__");
|
||||
@ -240,7 +240,7 @@ move_finalizers(PyGC_Head *unreachable, PyGC_Head *finalizers)
|
||||
}
|
||||
for (; gc != unreachable; gc=next) {
|
||||
PyObject *op = FROM_GC(gc);
|
||||
next = gc->gc_next;
|
||||
next = gc->gc.gc_next;
|
||||
if (PyInstance_Check(op) && PyObject_HasAttr(op, delstr)) {
|
||||
gc_list_remove(gc);
|
||||
gc_list_append(gc, finalizers);
|
||||
@ -253,8 +253,8 @@ static void
|
||||
move_finalizer_reachable(PyGC_Head *finalizers)
|
||||
{
|
||||
traverseproc traverse;
|
||||
PyGC_Head *gc = finalizers->gc_next;
|
||||
for (; gc != finalizers; gc=gc->gc_next) {
|
||||
PyGC_Head *gc = finalizers->gc.gc_next;
|
||||
for (; gc != finalizers; gc=gc->gc.gc_next) {
|
||||
/* careful, finalizers list is growing here */
|
||||
traverse = FROM_GC(gc)->ob_type->tp_traverse;
|
||||
(void) traverse(FROM_GC(gc),
|
||||
@ -297,8 +297,8 @@ handle_finalizers(PyGC_Head *finalizers, PyGC_Head *old)
|
||||
if (garbage == NULL) {
|
||||
garbage = PyList_New(0);
|
||||
}
|
||||
for (gc = finalizers->gc_next; gc != finalizers;
|
||||
gc = finalizers->gc_next) {
|
||||
for (gc = finalizers->gc.gc_next; gc != finalizers;
|
||||
gc = finalizers->gc.gc_next) {
|
||||
PyObject *op = FROM_GC(gc);
|
||||
if ((debug & DEBUG_SAVEALL) || PyInstance_Check(op)) {
|
||||
/* If SAVEALL is not set then just append
|
||||
@ -321,8 +321,8 @@ delete_garbage(PyGC_Head *unreachable, PyGC_Head *old)
|
||||
{
|
||||
inquiry clear;
|
||||
|
||||
while (unreachable->gc_next != unreachable) {
|
||||
PyGC_Head *gc = unreachable->gc_next;
|
||||
while (unreachable->gc.gc_next != unreachable) {
|
||||
PyGC_Head *gc = unreachable->gc.gc_next;
|
||||
PyObject *op = FROM_GC(gc);
|
||||
if (debug & DEBUG_SAVEALL) {
|
||||
PyList_Append(garbage, op);
|
||||
@ -334,7 +334,7 @@ delete_garbage(PyGC_Head *unreachable, PyGC_Head *old)
|
||||
Py_DECREF(op);
|
||||
}
|
||||
}
|
||||
if (unreachable->gc_next == gc) {
|
||||
if (unreachable->gc.gc_next == gc) {
|
||||
/* object is still alive, move it, it may die later */
|
||||
gc_list_remove(gc);
|
||||
gc_list_append(gc, old);
|
||||
@ -396,8 +396,8 @@ collect(PyGC_Head *young, PyGC_Head *old)
|
||||
|
||||
/* Collect statistics on collectable objects found and print
|
||||
* debugging information. */
|
||||
for (gc = unreachable.gc_next; gc != &unreachable;
|
||||
gc = gc->gc_next) {
|
||||
for (gc = unreachable.gc.gc_next; gc != &unreachable;
|
||||
gc = gc->gc.gc_next) {
|
||||
m++;
|
||||
if (debug & DEBUG_COLLECTABLE) {
|
||||
debug_cycle("collectable", FROM_GC(gc));
|
||||
@ -410,8 +410,8 @@ collect(PyGC_Head *young, PyGC_Head *old)
|
||||
|
||||
/* Collect statistics on uncollectable objects found and print
|
||||
* debugging information. */
|
||||
for (gc = finalizers.gc_next; gc != &finalizers;
|
||||
gc = gc->gc_next) {
|
||||
for (gc = finalizers.gc.gc_next; gc != &finalizers;
|
||||
gc = gc->gc.gc_next) {
|
||||
n++;
|
||||
if (debug & DEBUG_UNCOLLECTABLE) {
|
||||
debug_cycle("uncollectable", FROM_GC(gc));
|
||||
@ -456,7 +456,7 @@ collect_generations(void)
|
||||
generation = 2;
|
||||
gc_list_merge(&_PyGC_generation0, &generation2);
|
||||
gc_list_merge(&generation1, &generation2);
|
||||
if (generation2.gc_next != &generation2) {
|
||||
if (generation2.gc.gc_next != &generation2) {
|
||||
n = collect(&generation2, &generation2);
|
||||
}
|
||||
collections1 = 0;
|
||||
@ -465,7 +465,7 @@ collect_generations(void)
|
||||
generation = 1;
|
||||
collections1++;
|
||||
gc_list_merge(&_PyGC_generation0, &generation1);
|
||||
if (generation1.gc_next != &generation1) {
|
||||
if (generation1.gc.gc_next != &generation1) {
|
||||
n = collect(&generation1, &generation2);
|
||||
}
|
||||
collections0 = 0;
|
||||
@ -473,7 +473,7 @@ collect_generations(void)
|
||||
else {
|
||||
generation = 0;
|
||||
collections0++;
|
||||
if (_PyGC_generation0.gc_next != &_PyGC_generation0) {
|
||||
if (_PyGC_generation0.gc.gc_next != &_PyGC_generation0) {
|
||||
n = collect(&_PyGC_generation0, &generation1);
|
||||
}
|
||||
}
|
||||
@ -646,7 +646,7 @@ gc_referents_for(PyObject *objs, PyGC_Head *list, PyObject *resultlist)
|
||||
PyGC_Head *gc;
|
||||
PyObject *obj;
|
||||
traverseproc traverse;
|
||||
for (gc = list->gc_next; gc != list; gc = gc->gc_next) {
|
||||
for (gc = list->gc.gc_next; gc != list; gc = gc->gc.gc_next) {
|
||||
obj = FROM_GC(gc);
|
||||
traverse = obj->ob_type->tp_traverse;
|
||||
if (obj == objs || obj == resultlist)
|
||||
@ -688,7 +688,7 @@ static void
|
||||
append_objects(PyObject *py_list, PyGC_Head *gc_list)
|
||||
{
|
||||
PyGC_Head *gc;
|
||||
for (gc = gc_list->gc_next; gc != gc_list; gc = gc->gc_next) {
|
||||
for (gc = gc_list->gc.gc_next; gc != gc_list; gc = gc->gc.gc_next) {
|
||||
PyObject *op = FROM_GC(gc);
|
||||
if (op != py_list) {
|
||||
Py_INCREF(op);
|
||||
@ -807,7 +807,7 @@ _PyObject_GC_Malloc(PyTypeObject *tp, int nitems)
|
||||
PyGC_Head *g = PyObject_MALLOC(nbytes);
|
||||
if (g == NULL)
|
||||
return (PyObject *)PyErr_NoMemory();
|
||||
g->gc_next = NULL;
|
||||
g->gc.gc_next = NULL;
|
||||
allocated++;
|
||||
if (allocated > threshold0 &&
|
||||
enabled &&
|
||||
@ -866,7 +866,7 @@ _PyObject_GC_Del(PyObject *op)
|
||||
{
|
||||
#ifdef WITH_CYCLE_GC
|
||||
PyGC_Head *g = AS_GC(op);
|
||||
if (g->gc_next != NULL)
|
||||
if (g->gc.gc_next != NULL)
|
||||
gc_list_remove(g);
|
||||
if (allocated > 0) {
|
||||
allocated--;
|
||||
|
Loading…
Reference in New Issue
Block a user