Commit 0266f281 authored by Giuseppe Ottaviano's avatar Giuseppe Ottaviano Committed by Facebook Github Bot

Use sized deallocation in small_vector when possible

Summary: Capacity is known in almost all the modes (except when it's inferred from `malloc_usable_size`, which is probably something we should not do in the first place), so we can easily plug in sized deallocation.

Reviewed By: yfeldblum

Differential Revision: D19976657

fbshipit-source-id: cb03f7107195af614514645c88d12ac4999dea53
parent d0f956f5
...@@ -1103,16 +1103,24 @@ class small_vector : public detail::small_vector_base< ...@@ -1103,16 +1103,24 @@ class small_vector : public detail::small_vector_base<
newSize = std::max(newSize, computeNewSize()); newSize = std::max(newSize, computeNewSize());
auto needBytes = newSize * sizeof(value_type); const auto needBytes = newSize * sizeof(value_type);
// If the capacity isn't explicitly stored inline, but the heap // If the capacity isn't explicitly stored inline, but the heap
// allocation is grown to over some threshold, we should store // allocation is grown to over some threshold, we should store
// a capacity at the front of the heap allocation. // a capacity at the front of the heap allocation.
bool heapifyCapacity = const bool heapifyCapacity =
!kHasInlineCapacity && needBytes > kHeapifyCapacityThreshold; !kHasInlineCapacity && needBytes > kHeapifyCapacityThreshold;
if (heapifyCapacity) { const size_t allocationExtraBytes =
needBytes += kHeapifyCapacitySize; heapifyCapacity ? kHeapifyCapacitySize : 0;
} const size_t goodAllocationSizeBytes =
auto const sizeBytes = goodMallocSize(needBytes); goodMallocSize(needBytes + allocationExtraBytes);
const size_t newCapacity =
(goodAllocationSizeBytes - allocationExtraBytes) / sizeof(value_type);
// Make sure that the allocation request has a size computable from the
// capacity, instead of using goodAllocationSizeBytes, so that we can do
// sized deallocation. If goodMallocSize() gives us extra bytes that are not
// a multiple of the value size we cannot use them anyway.
const size_t sizeBytes =
newCapacity * sizeof(value_type) + allocationExtraBytes;
void* newh = checkedMalloc(sizeBytes); void* newh = checkedMalloc(sizeBytes);
// We expect newh to be at least 2-aligned, because we want to // We expect newh to be at least 2-aligned, because we want to
// use its least significant bit as a flag. // use its least significant bit as a flag.
...@@ -1124,7 +1132,7 @@ class small_vector : public detail::small_vector_base< ...@@ -1124,7 +1132,7 @@ class small_vector : public detail::small_vector_base<
{ {
auto rollback = makeGuard([&] { // auto rollback = makeGuard([&] { //
free(newh); sizedFree(newh, sizeBytes);
}); });
if (insert) { if (insert) {
// move and insert the new element // move and insert the new element
...@@ -1143,15 +1151,13 @@ class small_vector : public detail::small_vector_base< ...@@ -1143,15 +1151,13 @@ class small_vector : public detail::small_vector_base<
if (this->isExtern()) { if (this->isExtern()) {
u.freeHeap(); u.freeHeap();
} }
auto availableSizeBytes = sizeBytes;
if (heapifyCapacity) { if (heapifyCapacity) {
u.pdata_.heap_ = detail::pointerFlagSet(newh); u.pdata_.heap_ = detail::pointerFlagSet(newh);
availableSizeBytes -= kHeapifyCapacitySize;
} else { } else {
u.pdata_.heap_ = newh; u.pdata_.heap_ = newh;
} }
this->setExtern(true); this->setExtern(true);
this->setCapacity(availableSizeBytes / sizeof(value_type)); this->setCapacity(newCapacity);
} }
/* /*
...@@ -1177,6 +1183,9 @@ class small_vector : public detail::small_vector_base< ...@@ -1177,6 +1183,9 @@ class small_vector : public detail::small_vector_base<
void setCapacity(InternalSizeType c) { void setCapacity(InternalSizeType c) {
capacity_ = c; capacity_ = c;
} }
size_t allocationExtraBytes() const {
return 0;
}
} FOLLY_SV_PACK_ATTR; } FOLLY_SV_PACK_ATTR;
struct HeapPtr { struct HeapPtr {
...@@ -1191,6 +1200,10 @@ class small_vector : public detail::small_vector_base< ...@@ -1191,6 +1200,10 @@ class small_vector : public detail::small_vector_base<
void setCapacity(InternalSizeType c) { void setCapacity(InternalSizeType c) {
*static_cast<InternalSizeType*>(detail::pointerFlagClear(heap_)) = c; *static_cast<InternalSizeType*>(detail::pointerFlagClear(heap_)) = c;
} }
size_t allocationExtraBytes() const {
assert(detail::pointerFlagGet(heap_));
return kHeapifyCapacitySize;
}
} FOLLY_SV_PACK_ATTR; } FOLLY_SV_PACK_ATTR;
typedef aligned_storage_for_t<value_type[MaxInline]> InlineStorageDataType; typedef aligned_storage_for_t<value_type[MaxInline]> InlineStorageDataType;
...@@ -1255,8 +1268,15 @@ class small_vector : public detail::small_vector_base< ...@@ -1255,8 +1268,15 @@ class small_vector : public detail::small_vector_base<
void freeHeap() { void freeHeap() {
auto vp = detail::pointerFlagClear(pdata_.heap_); auto vp = detail::pointerFlagClear(pdata_.heap_);
if (hasCapacity()) {
sizedFree(
vp,
pdata_.getCapacity() * sizeof(value_type) +
pdata_.allocationExtraBytes());
} else {
free(vp); free(vp);
} }
}
} u; } u;
}; };
FOLLY_SV_PACK_POP FOLLY_SV_PACK_POP
......
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