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