zone.cc revision 589d6979ff2ef66fca2d8fa51404c369ca5e9250
1b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch// Copyright 2011 the V8 project authors. All rights reserved. 2a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Redistribution and use in source and binary forms, with or without 3a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// modification, are permitted provided that the following conditions are 4a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// met: 5a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// 6a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// * Redistributions of source code must retain the above copyright 7a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// notice, this list of conditions and the following disclaimer. 8a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// * Redistributions in binary form must reproduce the above 9a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// copyright notice, this list of conditions and the following 10a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// disclaimer in the documentation and/or other materials provided 11a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// with the distribution. 12a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// * Neither the name of Google Inc. nor the names of its 13a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// contributors may be used to endorse or promote products derived 14a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// from this software without specific prior written permission. 15a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// 16a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 28a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "v8.h" 29a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 30a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "zone-inl.h" 316ded16be15dd865a9b21ea304d5273c8be299c87Steve Block#include "splay-tree-inl.h" 32a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 33a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace v8 { 34a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace internal { 35a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 36a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 37a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Segments represent chunks of memory: They have starting address 38a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// (encoded in the this pointer) and a size in bytes. Segments are 39a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// chained together forming a LIFO structure with the newest segment 4044f0eee88ff00398ff7f715fab053374d808c90dSteve Block// available as segment_head_. Segments are allocated using malloc() 41a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// and de-allocated using free(). 42a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 43a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass Segment { 44a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public: 4569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch void Initialize(Segment* next, int size) { 4669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch next_ = next; 4769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch size_ = size; 4869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } 4969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 50a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Segment* next() const { return next_; } 51a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block void clear_next() { next_ = NULL; } 52a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 53a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int size() const { return size_; } 54a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int capacity() const { return size_ - sizeof(Segment); } 55a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 56a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Address start() const { return address(sizeof(Segment)); } 57a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Address end() const { return address(size_); } 58a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 59a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private: 60a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Computes the address of the nth byte in this segment. 61a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Address address(int n) const { 62a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return Address(this) + n; 63a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 64a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 65a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Segment* next_; 66a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int size_; 67a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 68a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 69a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen MurdochZone::Zone() 7169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch : zone_excess_limit_(256 * MB), 7269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch segment_bytes_allocated_(0), 7369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch position_(0), 7469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch limit_(0), 7569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch scope_nesting_(0), 7669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch segment_head_(NULL) { 7769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch} 7869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdochunsigned Zone::allocation_size_ = 0; 7969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 8069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen MurdochZoneScope::~ZoneScope() { 8169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch ASSERT_EQ(Isolate::Current(), isolate_); 8269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch if (ShouldDeleteOnExit()) isolate_->zone()->DeleteAll(); 8369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch isolate_->zone()->scope_nesting_--; 8469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch} 8569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 8669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 8744f0eee88ff00398ff7f715fab053374d808c90dSteve Block// Creates a new segment, sets it size, and pushes it to the front 8844f0eee88ff00398ff7f715fab053374d808c90dSteve Block// of the segment chain. Returns the new segment. 8944f0eee88ff00398ff7f715fab053374d808c90dSteve BlockSegment* Zone::NewSegment(int size) { 9044f0eee88ff00398ff7f715fab053374d808c90dSteve Block Segment* result = reinterpret_cast<Segment*>(Malloced::New(size)); 9144f0eee88ff00398ff7f715fab053374d808c90dSteve Block adjust_segment_bytes_allocated(size); 9244f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (result != NULL) { 9369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch result->Initialize(segment_head_, size); 9444f0eee88ff00398ff7f715fab053374d808c90dSteve Block segment_head_ = result; 9544f0eee88ff00398ff7f715fab053374d808c90dSteve Block } 9644f0eee88ff00398ff7f715fab053374d808c90dSteve Block return result; 9744f0eee88ff00398ff7f715fab053374d808c90dSteve Block} 9844f0eee88ff00398ff7f715fab053374d808c90dSteve Block 9944f0eee88ff00398ff7f715fab053374d808c90dSteve Block 10044f0eee88ff00398ff7f715fab053374d808c90dSteve Block// Deletes the given segment. Does not touch the segment chain. 10144f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid Zone::DeleteSegment(Segment* segment, int size) { 10244f0eee88ff00398ff7f715fab053374d808c90dSteve Block adjust_segment_bytes_allocated(-size); 10344f0eee88ff00398ff7f715fab053374d808c90dSteve Block Malloced::Delete(segment); 10444f0eee88ff00398ff7f715fab053374d808c90dSteve Block} 105a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 106a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 107a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid Zone::DeleteAll() { 108a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef DEBUG 109a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Constant byte value used for zapping dead memory in debug mode. 110a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block static const unsigned char kZapDeadByte = 0xcd; 111a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif 112a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 113a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Find a segment with a suitable size to keep around. 11444f0eee88ff00398ff7f715fab053374d808c90dSteve Block Segment* keep = segment_head_; 115a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block while (keep != NULL && keep->size() > kMaximumKeptSegmentSize) { 116a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block keep = keep->next(); 117a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 118a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 119a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Traverse the chained list of segments, zapping (in debug mode) 120a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // and freeing every segment except the one we wish to keep. 12144f0eee88ff00398ff7f715fab053374d808c90dSteve Block Segment* current = segment_head_; 122a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block while (current != NULL) { 123a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Segment* next = current->next(); 124a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (current == keep) { 125a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Unlink the segment we wish to keep from the list. 126a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block current->clear_next(); 127a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 128a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int size = current->size(); 129a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef DEBUG 130a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Zap the entire current segment (including the header). 131a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block memset(current, kZapDeadByte, size); 132a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif 13344f0eee88ff00398ff7f715fab053374d808c90dSteve Block DeleteSegment(current, size); 134a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 135a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block current = next; 136a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 137a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 138a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If we have found a segment we want to keep, we must recompute the 139a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // variables 'position' and 'limit' to prepare for future allocate 140a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // attempts. Otherwise, we must clear the position and limit to 141a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // force a new segment to be allocated on demand. 142a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (keep != NULL) { 143a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Address start = keep->start(); 144a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block position_ = RoundUp(start, kAlignment); 145a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block limit_ = keep->end(); 146a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef DEBUG 147a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Zap the contents of the kept segment (but not the header). 148a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block memset(start, kZapDeadByte, keep->capacity()); 149a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif 150a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 151a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block position_ = limit_ = 0; 152a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 153a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 154a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Update the head segment to be the kept segment (if any). 15544f0eee88ff00398ff7f715fab053374d808c90dSteve Block segment_head_ = keep; 156a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 157a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 158a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 15969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdochvoid Zone::DeleteKeptSegment() { 16069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch if (segment_head_ != NULL) { 16169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch DeleteSegment(segment_head_, segment_head_->size()); 16269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch segment_head_ = NULL; 16369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch } 16469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch} 16569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 16669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 167a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockAddress Zone::NewExpand(int size) { 168a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Make sure the requested size is already properly aligned and that 169a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // there isn't enough room in the Zone to satisfy the request. 170a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(size == RoundDown(size, kAlignment)); 171589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch ASSERT(size > limit_ - position_); 172a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 173a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Compute the new segment size. We use a 'high water mark' 174a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // strategy, where we increase the segment size every time we expand 175a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // except that we employ a maximum segment size when we delete. This 176a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // is to avoid excessive malloc() and free() overhead. 17744f0eee88ff00398ff7f715fab053374d808c90dSteve Block Segment* head = segment_head_; 178a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int old_size = (head == NULL) ? 0 : head->size(); 179a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block static const int kSegmentOverhead = sizeof(Segment) + kAlignment; 180589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch int new_size_no_overhead = size + (old_size << 1); 181589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch int new_size = kSegmentOverhead + new_size_no_overhead; 182589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch // Guard against integer overflow. 183589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch if (new_size_no_overhead < size || new_size < kSegmentOverhead) { 184589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch V8::FatalProcessOutOfMemory("Zone"); 185589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch return NULL; 186589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch } 187a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (new_size < kMinimumSegmentSize) { 188a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block new_size = kMinimumSegmentSize; 189a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else if (new_size > kMaximumSegmentSize) { 190a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Limit the size of new segments to avoid growing the segment size 191a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // exponentially, thus putting pressure on contiguous virtual address space. 192a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // All the while making sure to allocate a segment large enough to hold the 193a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // requested size. 194a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block new_size = Max(kSegmentOverhead + size, kMaximumSegmentSize); 195a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 19644f0eee88ff00398ff7f715fab053374d808c90dSteve Block Segment* segment = NewSegment(new_size); 197a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (segment == NULL) { 198a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block V8::FatalProcessOutOfMemory("Zone"); 199a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return NULL; 200a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 201a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 202a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Recompute 'top' and 'limit' based on the new segment. 203a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Address result = RoundUp(segment->start(), kAlignment); 204a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block position_ = result + size; 205589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch // Check for address overflow. 206589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch if (position_ < result) { 207589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch V8::FatalProcessOutOfMemory("Zone"); 208589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch return NULL; 209589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch } 210a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block limit_ = segment->end(); 211a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(position_ <= limit_); 212a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return result; 213a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 214a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 215a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 216a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} } // namespace v8::internal 217