1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
8 #include "allocation.h"
13 #include "splay-tree.h"
18 #if defined(__has_feature)
19 #if __has_feature(address_sanitizer)
20 #define V8_USE_ADDRESS_SANITIZER
27 // The Zone supports very fast allocation of small chunks of
28 // memory. The chunks cannot be deallocated individually, but instead
29 // the Zone supports deallocating all chunks in one fast
30 // operation. The Zone is used to hold temporary data structures like
31 // the abstract syntax tree, which is deallocated after compilation.
33 // Note: There is no need to initialize the Zone; the first time an
34 // allocation is attempted, a segment of memory will be requested
35 // through a call to malloc().
37 // Note: The implementation is inherently not thread safe. Do not use
38 // from multi-threaded code.
42 explicit Zone(Isolate* isolate);
44 // Allocate 'size' bytes of memory in the Zone; expands the Zone by
45 // allocating new segments of memory on demand using malloc().
46 inline void* New(int size);
49 inline T* NewArray(int length);
51 // Deletes all objects and free all memory allocated in the Zone. Keeps one
52 // small (size <= kMaximumKeptSegmentSize) segment around if it finds one.
55 // Deletes the last small segment kept around by DeleteAll(). You
56 // may no longer allocate in the Zone after a call to this method.
57 void DeleteKeptSegment();
59 // Returns true if more memory has been allocated in zones than
61 inline bool excess_allocation();
63 inline void adjust_segment_bytes_allocated(int delta);
65 inline unsigned allocation_size() { return allocation_size_; }
67 inline Isolate* isolate() { return isolate_; }
72 // All pointers returned from New() have this alignment. In addition, if the
73 // object being allocated has a size that is divisible by 8 then its alignment
74 // will be 8. ASan requires 8-byte alignment.
75 #ifdef V8_USE_ADDRESS_SANITIZER
76 static const int kAlignment = 8;
77 STATIC_ASSERT(kPointerSize <= 8);
79 static const int kAlignment = kPointerSize;
82 // Never allocate segments smaller than this size in bytes.
83 static const int kMinimumSegmentSize = 8 * KB;
85 // Never allocate segments larger than this size in bytes.
86 static const int kMaximumSegmentSize = 1 * MB;
88 // Never keep segments larger than this size in bytes around.
89 static const int kMaximumKeptSegmentSize = 64 * KB;
91 // Report zone excess when allocation exceeds this limit.
92 static const int kExcessLimit = 256 * MB;
94 // The number of bytes allocated in this zone so far.
95 unsigned allocation_size_;
97 // The number of bytes allocated in segments. Note that this number
98 // includes memory allocated from the OS but not yet allocated from
100 int segment_bytes_allocated_;
102 // Expand the Zone to hold at least 'size' more bytes and allocate
103 // the bytes. Returns the address of the newly allocated chunk of
104 // memory in the Zone. Should only be called if there isn't enough
105 // room in the Zone already.
106 Address NewExpand(int size);
108 // Creates a new segment, sets it size, and pushes it to the front
109 // of the segment chain. Returns the new segment.
110 INLINE(Segment* NewSegment(int size));
112 // Deletes the given segment. Does not touch the segment chain.
113 INLINE(void DeleteSegment(Segment* segment, int size));
115 // The free region in the current (front) segment is represented as
116 // the half-open interval [position, limit). The 'position' variable
117 // is guaranteed to be aligned as dictated by kAlignment.
121 Segment* segment_head_;
126 // ZoneObject is an abstraction that helps define classes of objects
127 // allocated in the Zone. Use it as a base class; see ast.h.
130 // Allocate a new ZoneObject of 'size' bytes in the Zone.
131 INLINE(void* operator new(size_t size, Zone* zone));
133 // Ideally, the delete operator should be private instead of
134 // public, but unfortunately the compiler sometimes synthesizes
135 // (unused) destructors for classes derived from ZoneObject, which
136 // require the operator to be visible. MSVC requires the delete
137 // operator to be public.
139 // ZoneObjects should never be deleted individually; use
140 // Zone::DeleteAll() to delete all zone objects in one go.
141 void operator delete(void*, size_t) { UNREACHABLE(); }
142 void operator delete(void* pointer, Zone* zone) { UNREACHABLE(); }
146 // The ZoneScope is used to automatically call DeleteAll() on a
147 // Zone when the ZoneScope is destroyed (i.e. goes out of scope)
150 explicit ZoneScope(Zone* zone) : zone_(zone) { }
151 ~ZoneScope() { zone_->DeleteAll(); }
153 Zone* zone() { return zone_; }
160 // The ZoneAllocationPolicy is used to specialize generic data
161 // structures to allocate themselves and their elements in the Zone.
162 struct ZoneAllocationPolicy {
164 explicit ZoneAllocationPolicy(Zone* zone) : zone_(zone) { }
165 INLINE(void* New(size_t size));
166 INLINE(static void Delete(void *pointer)) { }
167 Zone* zone() { return zone_; }
174 // ZoneLists are growable lists with constant-time access to the
175 // elements. The list itself and all its elements are allocated in the
176 // Zone. ZoneLists cannot be deleted individually; you can delete all
177 // objects in the Zone by calling Zone::DeleteAll().
179 class ZoneList: public List<T, ZoneAllocationPolicy> {
181 // Construct a new ZoneList with the given capacity; the length is
182 // always zero. The capacity must be non-negative.
183 ZoneList(int capacity, Zone* zone)
184 : List<T, ZoneAllocationPolicy>(capacity, ZoneAllocationPolicy(zone)) { }
186 INLINE(void* operator new(size_t size, Zone* zone));
188 // Construct a new ZoneList by copying the elements of the given ZoneList.
189 ZoneList(const ZoneList<T>& other, Zone* zone)
190 : List<T, ZoneAllocationPolicy>(other.length(),
191 ZoneAllocationPolicy(zone)) {
195 // We add some convenience wrappers so that we can pass in a Zone
196 // instead of a (less convenient) ZoneAllocationPolicy.
197 INLINE(void Add(const T& element, Zone* zone)) {
198 List<T, ZoneAllocationPolicy>::Add(element, ZoneAllocationPolicy(zone));
200 INLINE(void AddAll(const List<T, ZoneAllocationPolicy>& other, Zone* zone)) {
201 List<T, ZoneAllocationPolicy>::AddAll(other, ZoneAllocationPolicy(zone));
203 INLINE(void AddAll(const Vector<T>& other, Zone* zone)) {
204 List<T, ZoneAllocationPolicy>::AddAll(other, ZoneAllocationPolicy(zone));
206 INLINE(void InsertAt(int index, const T& element, Zone* zone)) {
207 List<T, ZoneAllocationPolicy>::InsertAt(index, element,
208 ZoneAllocationPolicy(zone));
210 INLINE(Vector<T> AddBlock(T value, int count, Zone* zone)) {
211 return List<T, ZoneAllocationPolicy>::AddBlock(value, count,
212 ZoneAllocationPolicy(zone));
214 INLINE(void Allocate(int length, Zone* zone)) {
215 List<T, ZoneAllocationPolicy>::Allocate(length, ZoneAllocationPolicy(zone));
217 INLINE(void Initialize(int capacity, Zone* zone)) {
218 List<T, ZoneAllocationPolicy>::Initialize(capacity,
219 ZoneAllocationPolicy(zone));
222 void operator delete(void* pointer) { UNREACHABLE(); }
223 void operator delete(void* pointer, Zone* zone) { UNREACHABLE(); }
227 // A zone splay tree. The config type parameter encapsulates the
228 // different configurations of a concrete splay tree (see splay-tree.h).
229 // The tree itself and all its elements are allocated in the Zone.
230 template <typename Config>
231 class ZoneSplayTree: public SplayTree<Config, ZoneAllocationPolicy> {
233 explicit ZoneSplayTree(Zone* zone)
234 : SplayTree<Config, ZoneAllocationPolicy>(ZoneAllocationPolicy(zone)) {}
237 INLINE(void* operator new(size_t size, Zone* zone));
239 void operator delete(void* pointer) { UNREACHABLE(); }
240 void operator delete(void* pointer, Zone* zone) { UNREACHABLE(); }
244 typedef TemplateHashMapImpl<ZoneAllocationPolicy> ZoneHashMap;
246 } } // namespace v8::internal