Index: src/zone.h |
diff --git a/src/zone.h b/src/zone.h |
index 29055cb70d053547d44091cdfaf420e0f6736e2d..0b5b41c80a9f5b4e54701a41b49226df4f0318fc 100644 |
--- a/src/zone.h |
+++ b/src/zone.h |
@@ -10,6 +10,7 @@ |
#include "src/base/accounting-allocator.h" |
#include "src/base/hashmap.h" |
#include "src/base/logging.h" |
+#include "src/base/platform/platform.h" |
#include "src/globals.h" |
#include "src/list.h" |
#include "src/splay-tree.h" |
@@ -66,7 +67,13 @@ class Zone final { |
base::AccountingAllocator* allocator() const { return allocator_; } |
+ // Returns the zone the pointer belongs to. Only works in case the pointer |
+ // actually lies within a zone segment. |
+ static Zone* GetZoneFromPointer(const void* ptr); |
+ |
private: |
+ friend class ZoneObject; |
+ friend class Segment; |
// All pointers returned from New() have this alignment. In addition, if the |
// object being allocated has a size that is divisible by 8 then its alignment |
// will be 8. ASan requires 8-byte alignment. |
@@ -83,12 +90,24 @@ class Zone final { |
// Never allocate segments larger than this size in bytes. |
static const size_t kMaximumSegmentSize = 1 * MB; |
+ static const uint8_t kSegmentAlignmentBits = 20; |
+ |
+ // Always align new segments to this size. |
+ static const size_t kSegmentAlignmentSize = 1 << kSegmentAlignmentBits; |
+ |
+ static const size_t kSegmentAlignmentMask = |
+ ~((1 << kSegmentAlignmentBits) - 1); |
+ |
+ STATIC_ASSERT(kMaximumSegmentSize <= kSegmentAlignmentSize); |
+ |
// Never keep segments larger than this size in bytes around. |
static const size_t kMaximumKeptSegmentSize = 64 * KB; |
// Report zone excess when allocation exceeds this limit. |
static const size_t kExcessLimit = 256 * MB; |
+ static Segment* GetZoneSegmentFromPointer(const void* ptr); |
+ |
// The number of bytes allocated in this zone so far. |
size_t allocation_size_; |
@@ -97,18 +116,19 @@ class Zone final { |
// the zone. |
size_t segment_bytes_allocated_; |
- // Expand the Zone to hold at least 'size' more bytes and allocate |
- // the bytes. Returns the address of the newly allocated chunk of |
- // memory in the Zone. Should only be called if there isn't enough |
- // room in the Zone already. |
- Address NewExpand(size_t size); |
+ // Creates a new normal segment, that can be used to quickly allocate memory |
+ // for lots of smaller objects. |
+ Address NewNormalSegment(size_t size); |
- // Creates a new segment, sets it size, and pushes it to the front |
- // of the segment chain. Returns the new segment. |
- inline Segment* NewSegment(size_t size); |
+ // Creates a large object segment, that is created to exactly fit one large |
+ // object. |
+ Address NewLargeObjectSegment(size_t size); |
+ |
+ size_t CalculateSegmentSize(const size_t requested); |
- // Deletes the given segment. Does not touch the segment chain. |
- inline void DeleteSegment(Segment* segment, size_t size); |
+ // Creates a new segment of the requested size and initializes it. Returns the |
+ // new segment. |
+ inline Segment* NewSegment(size_t size); |
// The free region in the current (front) segment is represented as |
// the half-open interval [position, limit). The 'position' variable |
@@ -121,7 +141,6 @@ class Zone final { |
Segment* segment_head_; |
}; |
- |
// ZoneObject is an abstraction that helps define classes of objects |
// allocated in the Zone. Use it as a base class; see ast.h. |
class ZoneObject { |
@@ -129,6 +148,8 @@ class ZoneObject { |
// Allocate a new ZoneObject of 'size' bytes in the Zone. |
void* operator new(size_t size, Zone* zone) { return zone->New(size); } |
+ Zone* zone() const { return Zone::GetZoneFromPointer(this); } |
+ |
// Ideally, the delete operator should be private instead of |
// public, but unfortunately the compiler sometimes synthesizes |
// (unused) destructors for classes derived from ZoneObject, which |
@@ -162,7 +183,9 @@ class ZoneAllocationPolicy final { |
public: |
explicit ZoneAllocationPolicy(Zone* zone) : zone_(zone) { } |
void* New(size_t size) { return zone()->New(size); } |
- static void Delete(void* pointer) {} |
+ static void Delete(void* pointer) { |
+ DCHECK_IMPLIES(pointer != nullptr, Zone::GetZoneFromPointer(pointer)); |
+ } |
Zone* zone() const { return zone_; } |
private: |
@@ -179,8 +202,9 @@ class ZoneList final : public List<T, ZoneAllocationPolicy> { |
public: |
// Construct a new ZoneList with the given capacity; the length is |
// always zero. The capacity must be non-negative. |
+ // The lists storage will be placed in the given zone. |
ZoneList(int capacity, Zone* zone) |
- : List<T, ZoneAllocationPolicy>(capacity, ZoneAllocationPolicy(zone)) { } |
+ : List<T, ZoneAllocationPolicy>(capacity, ZoneAllocationPolicy(zone)) {} |
void* operator new(size_t size, Zone* zone) { return zone->New(size); } |
@@ -191,33 +215,53 @@ class ZoneList final : public List<T, ZoneAllocationPolicy> { |
AddAll(other, zone); |
} |
- // We add some convenience wrappers so that we can pass in a Zone |
- // instead of a (less convenient) ZoneAllocationPolicy. |
void Add(const T& element, Zone* zone) { |
+ DCHECK_IMPLIES(this->has_storage_zone(), this->storage_zone() == zone); |
List<T, ZoneAllocationPolicy>::Add(element, ZoneAllocationPolicy(zone)); |
} |
+ |
void AddAll(const List<T, ZoneAllocationPolicy>& other, Zone* zone) { |
+ DCHECK_IMPLIES(this->has_storage_zone(), this->storage_zone() == zone); |
List<T, ZoneAllocationPolicy>::AddAll(other, ZoneAllocationPolicy(zone)); |
} |
+ |
void AddAll(const Vector<T>& other, Zone* zone) { |
+ DCHECK_IMPLIES(this->has_storage_zone(), this->storage_zone() == zone); |
List<T, ZoneAllocationPolicy>::AddAll(other, ZoneAllocationPolicy(zone)); |
} |
+ |
void InsertAt(int index, const T& element, Zone* zone) { |
+ DCHECK_IMPLIES(this->has_storage_zone(), this->storage_zone() == zone); |
List<T, ZoneAllocationPolicy>::InsertAt(index, element, |
ZoneAllocationPolicy(zone)); |
} |
+ |
Vector<T> AddBlock(T value, int count, Zone* zone) { |
+ DCHECK_IMPLIES(this->has_storage_zone(), this->storage_zone() == zone); |
return List<T, ZoneAllocationPolicy>::AddBlock(value, count, |
ZoneAllocationPolicy(zone)); |
} |
+ |
void Allocate(int length, Zone* zone) { |
+ DCHECK_IMPLIES(this->has_storage_zone(), this->storage_zone() == zone); |
List<T, ZoneAllocationPolicy>::Allocate(length, ZoneAllocationPolicy(zone)); |
} |
+ |
void Initialize(int capacity, Zone* zone) { |
+ DCHECK_IMPLIES(this->has_storage_zone(), this->storage_zone() == zone); |
List<T, ZoneAllocationPolicy>::Initialize(capacity, |
ZoneAllocationPolicy(zone)); |
} |
+ bool has_storage_zone() const { return this->capacity() > 0; } |
+ |
+ // Returns the zone the storage is located in |
+ Zone* storage_zone() const { |
+ DCHECK(this->has_storage_zone()); |
+ // ZoneList storage lives in a zone, so this works. |
+ return Zone::GetZoneFromPointer(this->data()); |
+ } |
+ |
void operator delete(void* pointer) { UNREACHABLE(); } |
void operator delete(void* pointer, Zone* zone) { UNREACHABLE(); } |
}; |