blob: 01df4504fe5ea8afc91ae90283a26fb53d8605d0 [file] [log] [blame]
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001// Copyright 2006-2008 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
30#include "zone-inl.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000031#include "splay-tree-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000032
kasperl@chromium.org71affb52009-05-26 05:44:31 +000033namespace v8 {
34namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000035
36
37Address Zone::position_ = 0;
38Address Zone::limit_ = 0;
ager@chromium.orga74f0da2008-12-03 16:05:52 +000039int Zone::zone_excess_limit_ = 256 * MB;
40int Zone::segment_bytes_allocated_ = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000041
42bool AssertNoZoneAllocation::allow_allocation_ = true;
43
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000044int ZoneScope::nesting_ = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000045
46// Segments represent chunks of memory: They have starting address
47// (encoded in the this pointer) and a size in bytes. Segments are
48// chained together forming a LIFO structure with the newest segment
49// available as Segment::head(). Segments are allocated using malloc()
50// and de-allocated using free().
51
52class Segment {
53 public:
54 Segment* next() const { return next_; }
55 void clear_next() { next_ = NULL; }
56
57 int size() const { return size_; }
58 int capacity() const { return size_ - sizeof(Segment); }
59
60 Address start() const { return address(sizeof(Segment)); }
61 Address end() const { return address(size_); }
62
63 static Segment* head() { return head_; }
64 static void set_head(Segment* head) { head_ = head; }
65
66 // Creates a new segment, sets it size, and pushes it to the front
67 // of the segment chain. Returns the new segment.
68 static Segment* New(int size) {
69 Segment* result = reinterpret_cast<Segment*>(Malloced::New(size));
ager@chromium.orga74f0da2008-12-03 16:05:52 +000070 Zone::adjust_segment_bytes_allocated(size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000071 if (result != NULL) {
72 result->next_ = head_;
73 result->size_ = size;
74 head_ = result;
75 }
76 return result;
77 }
78
79 // Deletes the given segment. Does not touch the segment chain.
ager@chromium.orga74f0da2008-12-03 16:05:52 +000080 static void Delete(Segment* segment, int size) {
81 Zone::adjust_segment_bytes_allocated(-size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000082 Malloced::Delete(segment);
83 }
84
ager@chromium.orga74f0da2008-12-03 16:05:52 +000085 static int bytes_allocated() { return bytes_allocated_; }
86
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000087 private:
88 // Computes the address of the nth byte in this segment.
89 Address address(int n) const {
90 return Address(this) + n;
91 }
92
93 static Segment* head_;
ager@chromium.orga74f0da2008-12-03 16:05:52 +000094 static int bytes_allocated_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000095 Segment* next_;
96 int size_;
97};
98
99
100Segment* Segment::head_ = NULL;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000101int Segment::bytes_allocated_ = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000102
103
104void Zone::DeleteAll() {
105#ifdef DEBUG
106 // Constant byte value used for zapping dead memory in debug mode.
107 static const unsigned char kZapDeadByte = 0xcd;
108#endif
109
110 // Find a segment with a suitable size to keep around.
111 Segment* keep = Segment::head();
112 while (keep != NULL && keep->size() > kMaximumKeptSegmentSize) {
113 keep = keep->next();
114 }
115
116 // Traverse the chained list of segments, zapping (in debug mode)
117 // and freeing every segment except the one we wish to keep.
118 Segment* current = Segment::head();
119 while (current != NULL) {
120 Segment* next = current->next();
121 if (current == keep) {
122 // Unlink the segment we wish to keep from the list.
123 current->clear_next();
124 } else {
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000125 int size = current->size();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000126#ifdef DEBUG
127 // Zap the entire current segment (including the header).
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000128 memset(current, kZapDeadByte, size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000129#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000130 Segment::Delete(current, size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000131 }
132 current = next;
133 }
134
135 // If we have found a segment we want to keep, we must recompute the
136 // variables 'position' and 'limit' to prepare for future allocate
137 // attempts. Otherwise, we must clear the position and limit to
138 // force a new segment to be allocated on demand.
139 if (keep != NULL) {
140 Address start = keep->start();
141 position_ = RoundUp(start, kAlignment);
142 limit_ = keep->end();
143#ifdef DEBUG
144 // Zap the contents of the kept segment (but not the header).
145 memset(start, kZapDeadByte, keep->capacity());
146#endif
147 } else {
148 position_ = limit_ = 0;
149 }
150
151 // Update the head segment to be the kept segment (if any).
152 Segment::set_head(keep);
153}
154
155
156Address Zone::NewExpand(int size) {
157 // Make sure the requested size is already properly aligned and that
158 // there isn't enough room in the Zone to satisfy the request.
159 ASSERT(size == RoundDown(size, kAlignment));
160 ASSERT(position_ + size > limit_);
161
162 // Compute the new segment size. We use a 'high water mark'
163 // strategy, where we increase the segment size every time we expand
164 // except that we employ a maximum segment size when we delete. This
165 // is to avoid excessive malloc() and free() overhead.
166 Segment* head = Segment::head();
167 int old_size = (head == NULL) ? 0 : head->size();
ager@chromium.org8bb60582008-12-11 12:02:20 +0000168 static const int kSegmentOverhead = sizeof(Segment) + kAlignment;
169 int new_size = kSegmentOverhead + size + (old_size << 1);
170 if (new_size < kMinimumSegmentSize) {
171 new_size = kMinimumSegmentSize;
172 } else if (new_size > kMaximumSegmentSize) {
173 // Limit the size of new segments to avoid growing the segment size
174 // exponentially, thus putting pressure on contiguous virtual address space.
175 // All the while making sure to allocate a segment large enough to hold the
176 // requested size.
177 new_size = Max(kSegmentOverhead + size, kMaximumSegmentSize);
178 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000179 Segment* segment = Segment::New(new_size);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000180 if (segment == NULL) {
181 V8::FatalProcessOutOfMemory("Zone");
182 return NULL;
183 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000184
185 // Recompute 'top' and 'limit' based on the new segment.
186 Address result = RoundUp(segment->start(), kAlignment);
187 position_ = result + size;
188 limit_ = segment->end();
189 ASSERT(position_ <= limit_);
190 return result;
191}
192
193
194} } // namespace v8::internal