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