Line data Source code
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>
48 : T* NewArray(size_t length) {
49 : DCHECK_LT(length, std::numeric_limits<size_t>::max() / sizeof(T));
50 701555742 : return static_cast<T*>(New(length * sizeof(T)));
51 : }
52 :
53 : // Seals the zone to prevent any further allocation.
54 0 : void Seal() { sealed_ = true; }
55 :
56 : // Returns true if more memory has been allocated in zones than
57 : // the limit allows.
58 : bool excess_allocation() const {
59 : return segment_bytes_allocated_ > kExcessLimit;
60 : }
61 :
62 : const char* name() const { return name_; }
63 :
64 : size_t allocation_size() const { return allocation_size_; }
65 :
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.
120 1324252538 : 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.
130 0 : void operator delete(void*, size_t) { UNREACHABLE(); }
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:
138 1073004339 : explicit ZoneAllocationPolicy(Zone* zone) : zone_(zone) {}
139 660957938 : void* New(size_t size) { return zone()->New(size); }
140 : static void Delete(void* pointer) {}
141 351013884 : 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.
156 323237808 : ZoneList(int capacity, Zone* zone)
157 323237739 : : List<T, ZoneAllocationPolicy>(capacity, ZoneAllocationPolicy(zone)) {}
158 :
159 : // Construct a new ZoneList from a std::initializer_list
160 10540 : ZoneList(std::initializer_list<T> list, Zone* zone)
161 : : List<T, ZoneAllocationPolicy>(static_cast<int>(list.size()),
162 10540 : ZoneAllocationPolicy(zone)) {
163 31830 : for (auto& i : list) Add(i, zone);
164 10540 : }
165 :
166 56672965 : 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.
169 2424849 : ZoneList(const ZoneList<T>& other, Zone* zone)
170 : : List<T, ZoneAllocationPolicy>(other.length(),
171 2424849 : ZoneAllocationPolicy(zone)) {
172 : AddAll(other, zone);
173 2424853 : }
174 :
175 : // We add some convenience wrappers so that we can pass in a Zone
176 : // instead of a (less convenient) ZoneAllocationPolicy.
177 247774718 : void Add(const T& element, Zone* zone) {
178 1042378281 : List<T, ZoneAllocationPolicy>::Add(element, ZoneAllocationPolicy(zone));
179 245360295 : }
180 : void AddAll(const List<T, ZoneAllocationPolicy>& other, Zone* zone) {
181 17500656 : List<T, ZoneAllocationPolicy>::AddAll(other, ZoneAllocationPolicy(zone));
182 : }
183 : void AddAll(const Vector<T>& other, Zone* zone) {
184 : List<T, ZoneAllocationPolicy>::AddAll(other, ZoneAllocationPolicy(zone));
185 : }
186 : void InsertAt(int index, const T& element, Zone* zone) {
187 6575676 : List<T, ZoneAllocationPolicy>::InsertAt(index, element,
188 13150694 : ZoneAllocationPolicy(zone));
189 : }
190 12191913 : Vector<T> AddBlock(T value, int count, Zone* zone) {
191 : return List<T, ZoneAllocationPolicy>::AddBlock(value, count,
192 24383853 : ZoneAllocationPolicy(zone));
193 : }
194 : void Allocate(int length, Zone* zone) {
195 : List<T, ZoneAllocationPolicy>::Allocate(length, ZoneAllocationPolicy(zone));
196 : }
197 785261 : void Initialize(int capacity, Zone* zone) {
198 : List<T, ZoneAllocationPolicy>::Initialize(capacity,
199 : ZoneAllocationPolicy(zone));
200 785261 : }
201 :
202 : void operator delete(void* pointer) { UNREACHABLE(); }
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:
212 : explicit ZoneSplayTree(Zone* zone)
213 : : SplayTree<Config, ZoneAllocationPolicy>(ZoneAllocationPolicy(zone)) {}
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 :
221 1635717 : void* operator new(size_t size, Zone* zone) { return zone->New(size); }
222 :
223 : void operator delete(void* pointer) { UNREACHABLE(); }
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_
|