mirror of
https://github.com/boostorg/python.git
synced 2026-01-23 05:42:30 +00:00
Respect alignment of by-value storage.
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
|
||||
#include <boost/python/detail/prefix.hpp>
|
||||
#include <boost/mpl/lambda.hpp> // #including this first is an intel6 workaround
|
||||
#include <boost/cstdint.hpp>
|
||||
|
||||
#include <boost/python/object/class.hpp>
|
||||
#include <boost/python/object/instance.hpp>
|
||||
@@ -721,28 +722,47 @@ namespace objects
|
||||
} // namespace objects
|
||||
|
||||
|
||||
void* instance_holder::allocate(PyObject* self_, std::size_t holder_offset, std::size_t holder_size)
|
||||
typedef unsigned int alignment_marker_t;
|
||||
|
||||
void* instance_holder::allocate(PyObject* self_, std::size_t holder_offset, std::size_t holder_size, std::size_t alignment)
|
||||
{
|
||||
assert(PyType_IsSubtype(Py_TYPE(Py_TYPE(self_)), &class_metatype_object));
|
||||
objects::instance<>* self = (objects::instance<>*)self_;
|
||||
|
||||
int total_size_needed = holder_offset + holder_size;
|
||||
int total_size_needed = holder_offset + holder_size + alignment - 1;
|
||||
|
||||
if (-Py_SIZE(self) >= total_size_needed)
|
||||
{
|
||||
// holder_offset should at least point into the variable-sized part
|
||||
assert(holder_offset >= offsetof(objects::instance<>,storage));
|
||||
|
||||
size_t allocated = holder_size + alignment;
|
||||
void* storage = (char*)self + holder_offset;
|
||||
void* aligned_storage = ::boost::alignment::align(alignment, holder_size, storage, allocated);
|
||||
|
||||
// Record the fact that the storage is occupied, noting where it starts
|
||||
Py_SET_SIZE(self, holder_offset);
|
||||
return (char*)self + holder_offset;
|
||||
const size_t offset = reinterpret_cast<uintptr_t>(aligned_storage) - reinterpret_cast<uintptr_t>(storage) + holder_offset;
|
||||
Py_SET_SIZE(self, offset);
|
||||
return (char*)self + offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
void* const result = PyMem_Malloc(holder_size);
|
||||
if (result == 0)
|
||||
const size_t base_allocation = sizeof(alignment_marker_t) + holder_size + alignment - 1;
|
||||
void* const base_storage = PyMem_Malloc(base_allocation);
|
||||
if (base_storage == 0)
|
||||
throw std::bad_alloc();
|
||||
return result;
|
||||
|
||||
const uintptr_t x = reinterpret_cast<uintptr_t>(base_storage) + sizeof(alignment_marker_t);
|
||||
//this has problems for x -> max(void *)
|
||||
//const size_t padding = alignment - ((x + sizeof(alignment_marker_t)) % alignment);
|
||||
//only works for alignments with alignments of powers of 2, but no edge conditions
|
||||
const uintptr_t padding = alignment == 1 ? 0 : ( alignment - (x & (alignment - 1)) );
|
||||
const size_t aligned_offset = sizeof(alignment_marker_t) + padding;
|
||||
void* const aligned_storage = (char *)base_storage + aligned_offset;
|
||||
BOOST_ASSERT((char *) aligned_storage + holder_size <= (char *)base_storage + base_allocation);
|
||||
alignment_marker_t* const marker_storage = reinterpret_cast<alignment_marker_t *>((char *)aligned_storage - sizeof(alignment_marker_t));
|
||||
*marker_storage = static_cast<alignment_marker_t>(padding);
|
||||
return aligned_storage;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -752,7 +772,9 @@ void instance_holder::deallocate(PyObject* self_, void* storage) throw()
|
||||
objects::instance<>* self = (objects::instance<>*)self_;
|
||||
if (storage != (char*)self + Py_SIZE(self))
|
||||
{
|
||||
PyMem_Free(storage);
|
||||
alignment_marker_t* marker_storage = reinterpret_cast<alignment_marker_t *>((char *)storage - sizeof(alignment_marker_t));
|
||||
void *malloced_storage = (char *) storage - sizeof(alignment_marker_t) - (*marker_storage);
|
||||
PyMem_Free(malloced_storage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user