• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #ifndef V8_ZONE_H_
6 #define V8_ZONE_H_
7 
8 #include <limits>
9 
10 #include "src/base/accounting-allocator.h"
11 #include "src/base/hashmap.h"
12 #include "src/base/logging.h"
13 #include "src/globals.h"
14 #include "src/list.h"
15 #include "src/splay-tree.h"
16 
17 namespace v8 {
18 namespace internal {
19 
20 // Forward declarations.
21 class Segment;
22 
23 
24 // The Zone supports very fast allocation of small chunks of
25 // memory. The chunks cannot be deallocated individually, but instead
26 // the Zone supports deallocating all chunks in one fast
27 // operation. The Zone is used to hold temporary data structures like
28 // the abstract syntax tree, which is deallocated after compilation.
29 //
30 // Note: There is no need to initialize the Zone; the first time an
31 // allocation is attempted, a segment of memory will be requested
32 // through a call to malloc().
33 //
34 // Note: The implementation is inherently not thread safe. Do not use
35 // from multi-threaded code.
36 class Zone final {
37  public:
38   explicit Zone(base::AccountingAllocator* allocator);
39   ~Zone();
40 
41   // Allocate 'size' bytes of memory in the Zone; expands the Zone by
42   // allocating new segments of memory on demand using malloc().
43   void* New(size_t size);
44 
45   template <typename T>
NewArray(size_t length)46   T* NewArray(size_t length) {
47     DCHECK_LT(length, std::numeric_limits<size_t>::max() / sizeof(T));
48     return static_cast<T*>(New(length * sizeof(T)));
49   }
50 
51   // Deletes all objects and free all memory allocated in the Zone. Keeps one
52   // small (size <= kMaximumKeptSegmentSize) segment around if it finds one.
53   void DeleteAll();
54 
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();
58 
59   // Returns true if more memory has been allocated in zones than
60   // the limit allows.
excess_allocation()61   bool excess_allocation() const {
62     return segment_bytes_allocated_ > kExcessLimit;
63   }
64 
allocation_size()65   size_t allocation_size() const { return allocation_size_; }
66 
allocator()67   base::AccountingAllocator* allocator() const { return allocator_; }
68 
69  private:
70   // All pointers returned from New() have this alignment.  In addition, if the
71   // object being allocated has a size that is divisible by 8 then its alignment
72   // will be 8. ASan requires 8-byte alignment.
73 #ifdef V8_USE_ADDRESS_SANITIZER
74   static const size_t kAlignment = 8;
75   STATIC_ASSERT(kPointerSize <= 8);
76 #else
77   static const size_t kAlignment = kPointerSize;
78 #endif
79 
80   // Never allocate segments smaller than this size in bytes.
81   static const size_t kMinimumSegmentSize = 8 * KB;
82 
83   // Never allocate segments larger than this size in bytes.
84   static const size_t kMaximumSegmentSize = 1 * MB;
85 
86   // Never keep segments larger than this size in bytes around.
87   static const size_t kMaximumKeptSegmentSize = 64 * KB;
88 
89   // Report zone excess when allocation exceeds this limit.
90   static const size_t kExcessLimit = 256 * MB;
91 
92   // The number of bytes allocated in this zone so far.
93   size_t allocation_size_;
94 
95   // The number of bytes allocated in segments.  Note that this number
96   // includes memory allocated from the OS but not yet allocated from
97   // the zone.
98   size_t segment_bytes_allocated_;
99 
100   // Expand the Zone to hold at least 'size' more bytes and allocate
101   // the bytes. Returns the address of the newly allocated chunk of
102   // memory in the Zone. Should only be called if there isn't enough
103   // room in the Zone already.
104   Address NewExpand(size_t size);
105 
106   // Creates a new segment, sets it size, and pushes it to the front
107   // of the segment chain. Returns the new segment.
108   inline Segment* NewSegment(size_t size);
109 
110   // Deletes the given segment. Does not touch the segment chain.
111   inline void DeleteSegment(Segment* segment, size_t size);
112 
113   // The free region in the current (front) segment is represented as
114   // the half-open interval [position, limit). The 'position' variable
115   // is guaranteed to be aligned as dictated by kAlignment.
116   Address position_;
117   Address limit_;
118 
119   base::AccountingAllocator* allocator_;
120 
121   Segment* segment_head_;
122 };
123 
124 
125 // ZoneObject is an abstraction that helps define classes of objects
126 // allocated in the Zone. Use it as a base class; see ast.h.
127 class ZoneObject {
128  public:
129   // Allocate a new ZoneObject of 'size' bytes in the Zone.
new(size_t size,Zone * zone)130   void* operator new(size_t size, Zone* zone) { return zone->New(size); }
131 
132   // Ideally, the delete operator should be private instead of
133   // public, but unfortunately the compiler sometimes synthesizes
134   // (unused) destructors for classes derived from ZoneObject, which
135   // require the operator to be visible. MSVC requires the delete
136   // operator to be public.
137 
138   // ZoneObjects should never be deleted individually; use
139   // Zone::DeleteAll() to delete all zone objects in one go.
delete(void *,size_t)140   void operator delete(void*, size_t) { UNREACHABLE(); }
delete(void * pointer,Zone * zone)141   void operator delete(void* pointer, Zone* zone) { UNREACHABLE(); }
142 };
143 
144 
145 // The ZoneScope is used to automatically call DeleteAll() on a
146 // Zone when the ZoneScope is destroyed (i.e. goes out of scope)
147 class ZoneScope final {
148  public:
ZoneScope(Zone * zone)149   explicit ZoneScope(Zone* zone) : zone_(zone) { }
~ZoneScope()150   ~ZoneScope() { zone_->DeleteAll(); }
151 
zone()152   Zone* zone() const { return zone_; }
153 
154  private:
155   Zone* zone_;
156 };
157 
158 
159 // The ZoneAllocationPolicy is used to specialize generic data
160 // structures to allocate themselves and their elements in the Zone.
161 class ZoneAllocationPolicy final {
162  public:
ZoneAllocationPolicy(Zone * zone)163   explicit ZoneAllocationPolicy(Zone* zone) : zone_(zone) { }
New(size_t size)164   void* New(size_t size) { return zone()->New(size); }
Delete(void * pointer)165   static void Delete(void* pointer) {}
zone()166   Zone* zone() const { return zone_; }
167 
168  private:
169   Zone* zone_;
170 };
171 
172 
173 // ZoneLists are growable lists with constant-time access to the
174 // elements. The list itself and all its elements are allocated in the
175 // Zone. ZoneLists cannot be deleted individually; you can delete all
176 // objects in the Zone by calling Zone::DeleteAll().
177 template <typename T>
178 class ZoneList final : public List<T, ZoneAllocationPolicy> {
179  public:
180   // Construct a new ZoneList with the given capacity; the length is
181   // always zero. The capacity must be non-negative.
ZoneList(int capacity,Zone * zone)182   ZoneList(int capacity, Zone* zone)
183       : List<T, ZoneAllocationPolicy>(capacity, ZoneAllocationPolicy(zone)) { }
184 
new(size_t size,Zone * zone)185   void* operator new(size_t size, Zone* zone) { return zone->New(size); }
186 
187   // Construct a new ZoneList by copying the elements of the given ZoneList.
ZoneList(const ZoneList<T> & other,Zone * zone)188   ZoneList(const ZoneList<T>& other, Zone* zone)
189       : List<T, ZoneAllocationPolicy>(other.length(),
190                                       ZoneAllocationPolicy(zone)) {
191     AddAll(other, zone);
192   }
193 
194   // We add some convenience wrappers so that we can pass in a Zone
195   // instead of a (less convenient) ZoneAllocationPolicy.
Add(const T & element,Zone * zone)196   void Add(const T& element, Zone* zone) {
197     List<T, ZoneAllocationPolicy>::Add(element, ZoneAllocationPolicy(zone));
198   }
AddAll(const List<T,ZoneAllocationPolicy> & other,Zone * zone)199   void AddAll(const List<T, ZoneAllocationPolicy>& other, Zone* zone) {
200     List<T, ZoneAllocationPolicy>::AddAll(other, ZoneAllocationPolicy(zone));
201   }
AddAll(const Vector<T> & other,Zone * zone)202   void AddAll(const Vector<T>& other, Zone* zone) {
203     List<T, ZoneAllocationPolicy>::AddAll(other, ZoneAllocationPolicy(zone));
204   }
InsertAt(int index,const T & element,Zone * zone)205   void InsertAt(int index, const T& element, Zone* zone) {
206     List<T, ZoneAllocationPolicy>::InsertAt(index, element,
207                                             ZoneAllocationPolicy(zone));
208   }
AddBlock(T value,int count,Zone * zone)209   Vector<T> AddBlock(T value, int count, Zone* zone) {
210     return List<T, ZoneAllocationPolicy>::AddBlock(value, count,
211                                                    ZoneAllocationPolicy(zone));
212   }
Allocate(int length,Zone * zone)213   void Allocate(int length, Zone* zone) {
214     List<T, ZoneAllocationPolicy>::Allocate(length, ZoneAllocationPolicy(zone));
215   }
Initialize(int capacity,Zone * zone)216   void Initialize(int capacity, Zone* zone) {
217     List<T, ZoneAllocationPolicy>::Initialize(capacity,
218                                               ZoneAllocationPolicy(zone));
219   }
220 
delete(void * pointer)221   void operator delete(void* pointer) { UNREACHABLE(); }
delete(void * pointer,Zone * zone)222   void operator delete(void* pointer, Zone* zone) { UNREACHABLE(); }
223 };
224 
225 
226 // A zone splay tree.  The config type parameter encapsulates the
227 // different configurations of a concrete splay tree (see splay-tree.h).
228 // The tree itself and all its elements are allocated in the Zone.
229 template <typename Config>
230 class ZoneSplayTree final : public SplayTree<Config, ZoneAllocationPolicy> {
231  public:
ZoneSplayTree(Zone * zone)232   explicit ZoneSplayTree(Zone* zone)
233       : SplayTree<Config, ZoneAllocationPolicy>(ZoneAllocationPolicy(zone)) {}
~ZoneSplayTree()234   ~ZoneSplayTree() {
235     // Reset the root to avoid unneeded iteration over all tree nodes
236     // in the destructor.  For a zone-allocated tree, nodes will be
237     // freed by the Zone.
238     SplayTree<Config, ZoneAllocationPolicy>::ResetRoot();
239   }
240 
new(size_t size,Zone * zone)241   void* operator new(size_t size, Zone* zone) { return zone->New(size); }
242 
delete(void * pointer)243   void operator delete(void* pointer) { UNREACHABLE(); }
delete(void * pointer,Zone * zone)244   void operator delete(void* pointer, Zone* zone) { UNREACHABLE(); }
245 };
246 
247 typedef base::TemplateHashMapImpl<ZoneAllocationPolicy> ZoneHashMap;
248 
249 }  // namespace internal
250 }  // namespace v8
251 
252 #endif  // V8_ZONE_H_
253