Commit f665e516 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Copy CPython's float freelist

(we had already copied their int freelist)
parent 90fe1528
......@@ -41,6 +41,86 @@ extern "C" int float_pow_unboxed(double iv, double iw, double* res) noexcept;
namespace pyston {
/* Special free list -- see comments for same code in intobject.c. */
#define BLOCK_SIZE 1000 /* 1K less typical malloc overhead */
#define BHEAD_SIZE 8 /* Enough for a 64-bit pointer */
#define N_FLOATOBJECTS ((BLOCK_SIZE - BHEAD_SIZE) / sizeof(PyFloatObject))
struct _floatblock {
struct _floatblock* next;
PyFloatObject objects[N_FLOATOBJECTS];
};
typedef struct _floatblock PyFloatBlock;
static PyFloatBlock* block_list = NULL;
PyFloatObject* BoxedFloat::free_list = NULL;
PyFloatObject* BoxedFloat::fill_free_list(void) noexcept {
PyFloatObject* p, *q;
/* XXX Float blocks escape the object heap. Use PyObject_MALLOC ??? */
p = (PyFloatObject*)PyMem_MALLOC(sizeof(PyFloatBlock));
if (p == NULL)
return (PyFloatObject*)PyErr_NoMemory();
((PyFloatBlock*)p)->next = block_list;
block_list = (PyFloatBlock*)p;
p = &((PyFloatBlock*)p)->objects[0];
q = p + N_FLOATOBJECTS;
while (--q > p)
q->ob_type = (struct _typeobject*)(q - 1);
q->ob_type = NULL;
return p + N_FLOATOBJECTS - 1;
}
void BoxedFloat::tp_dealloc(Box* b) noexcept {
#ifdef DISABLE_INT_FREELIST
b->cls->tp_free(b);
#else
if (PyFloat_CheckExact(b)) {
PyFloatObject* v = (PyFloatObject*)(b);
v->ob_type = (struct _typeobject *)free_list;
free_list = v;
} else {
b->cls->tp_free(b);
}
#endif
}
extern "C" int PyFloat_ClearFreeList() noexcept {
PyFloatObject* p;
PyFloatBlock* list, *next;
int i;
int u; /* remaining unfreed ints per block */
int freelist_size = 0;
list = block_list;
block_list = NULL;
BoxedFloat::free_list = NULL;
while (list != NULL) {
u = 0;
for (i = 0, p = &list->objects[0]; i < N_FLOATOBJECTS; i++, p++) {
if (PyFloat_CheckExact((BoxedFloat*)p) && Py_REFCNT(p) != 0)
u++;
}
next = list->next;
if (u) {
list->next = block_list;
block_list = list;
for (i = 0, p = &list->objects[0]; i < N_FLOATOBJECTS; i++, p++) {
if (!PyFloat_CheckExact((BoxedFloat*)p) || Py_REFCNT(p) == 0) {
p->ob_type = (struct _typeobject*)BoxedFloat::free_list;
BoxedFloat::free_list = p;
}
}
} else {
PyMem_FREE(list);
}
freelist_size += u;
list = next;
}
return freelist_size;
}
extern "C" PyObject* PyFloat_FromDouble(double d) noexcept {
return boxFloat(d);
}
......@@ -1631,10 +1711,6 @@ static PyMethodDef float_methods[]
{ "is_integer", (PyCFunction)float_is_integer, METH_NOARGS, NULL },
{ "__format__", (PyCFunction)float__format__, METH_VARARGS, NULL } };
extern "C" int PyFloat_ClearFreeList() noexcept {
return 0; // number of entries cleared
}
void setupFloat() {
static PyNumberMethods float_as_number;
float_cls->tp_as_number = &float_as_number;
......
......@@ -87,27 +87,20 @@ PyIntObject* BoxedInt::fill_free_list(void) noexcept {
return p + N_INTOBJECTS - 1;
}
void BoxedInt::tp_dealloc(Box* v) noexcept {
void BoxedInt::tp_dealloc(Box* b) noexcept {
#ifdef DISABLE_INT_FREELIST
v->cls->tp_free(v);
b->cls->tp_free(b);
#else
if (PyInt_CheckExact(v)) {
BoxedInt::tp_free(v);
if (PyInt_CheckExact(b)) {
PyIntObject* v = (PyIntObject*)(b);
v->ob_type = (struct _typeobject *)free_list;
free_list = v;
} else {
v->cls->tp_free(v);
b->cls->tp_free(b);
}
#endif
}
void BoxedInt::tp_free(void* b) noexcept {
#ifdef DISABLE_INT_FREELIST
assert(0);
#endif
PyIntObject* v = static_cast<PyIntObject*>(b);
v->ob_type = (struct _typeobject *)free_list;
free_list = v;
}
extern "C" unsigned long PyInt_AsUnsignedLongMask(PyObject* op) noexcept {
if (op && PyInt_Check(op))
return PyInt_AS_LONG((PyIntObject*)op);
......
......@@ -4217,7 +4217,8 @@ void setupRuntime() {
complex_cls = new (0) BoxedClass(object_cls, 0, 0, sizeof(BoxedComplex), false, "complex", true, NULL, NULL, false);
long_cls = new (0) BoxedClass(object_cls, 0, 0, sizeof(BoxedLong), false, "long", true, NULL, NULL, false);
long_cls->tp_flags |= Py_TPFLAGS_LONG_SUBCLASS;
float_cls = new (0) BoxedClass(object_cls, 0, 0, sizeof(BoxedFloat), false, "float", true, NULL, NULL, false);
float_cls = new (0)
BoxedClass(object_cls, 0, 0, sizeof(BoxedFloat), false, "float", true, BoxedFloat::tp_dealloc, NULL, false);
function_cls = new (0) BoxedClass(object_cls, offsetof(BoxedFunction, attrs), offsetof(BoxedFunction, weakreflist),
sizeof(BoxedFunction), false, "function", false, functionDtor, NULL, true,
(traverseproc)func_traverse, NOCLEAR);
......
......@@ -475,20 +475,46 @@ public:
}
static void tp_dealloc(Box* b) noexcept;
static void tp_free(void* b) noexcept;
friend int PyInt_ClearFreeList() noexcept;
};
static_assert(sizeof(BoxedInt) == sizeof(PyIntObject), "");
static_assert(offsetof(BoxedInt, n) == offsetof(PyIntObject, ob_ival), "");
extern "C" int PyFloat_ClearFreeList() noexcept;
class BoxedFloat : public Box {
private:
static PyFloatObject* free_list;
static PyFloatObject* fill_free_list() noexcept;
public:
double d;
BoxedFloat(double d) __attribute__((visibility("default"))) : d(d) {}
DEFAULT_CLASS_SIMPLE(float_cls, false);
void* operator new(size_t size, BoxedClass* cls) __attribute__((visibility("default"))) {
return Box::operator new(size, cls);
}
// float uses a customized allocator, so we can't use DEFAULT_CLASS_SIMPLE (which inlines the default allocator)
void* operator new(size_t size) __attribute__((visibility("default"))) {
#ifdef DISABLE_INT_FREELIST
return Box::operator new(size, float_cls);
#else
if (unlikely(free_list == NULL)) {
free_list = fill_free_list();
assert(free_list);
}
PyFloatObject* v = free_list;
free_list = (PyFloatObject*)v->ob_type;
PyObject_INIT((BoxedFloat*)v, &PyFloat_Type);
return v;
#endif
}
static void tp_dealloc(Box* b) noexcept;
friend int PyFloat_ClearFreeList() noexcept;
};
static_assert(sizeof(BoxedFloat) == sizeof(PyFloatObject), "");
static_assert(offsetof(BoxedFloat, d) == offsetof(PyFloatObject, ob_fval), "");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment