13ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch// Copyright 2012 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
283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch#include <string.h>
2985b71799222b55eb5dd74ea26efe0c64ab655c8cBen Murdoch
303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch#include "v8.h"
31a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "zone-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