OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "vm/zone.h" | 5 #include "vm/zone.h" |
6 | 6 |
7 #include "platform/assert.h" | 7 #include "platform/assert.h" |
8 #include "platform/utils.h" | 8 #include "platform/utils.h" |
9 #include "vm/dart_api_state.h" | 9 #include "vm/dart_api_state.h" |
10 #include "vm/flags.h" | 10 #include "vm/flags.h" |
(...skipping 25 matching lines...) Expand all Loading... |
36 intptr_t size_; | 36 intptr_t size_; |
37 | 37 |
38 // Computes the address of the nth byte in this segment. | 38 // Computes the address of the nth byte in this segment. |
39 uword address(int n) { return reinterpret_cast<uword>(this) + n; } | 39 uword address(int n) { return reinterpret_cast<uword>(this) + n; } |
40 | 40 |
41 static void Delete(Segment* segment) { free(segment); } | 41 static void Delete(Segment* segment) { free(segment); } |
42 | 42 |
43 DISALLOW_IMPLICIT_CONSTRUCTORS(Segment); | 43 DISALLOW_IMPLICIT_CONSTRUCTORS(Segment); |
44 }; | 44 }; |
45 | 45 |
46 | |
47 Zone::Segment* Zone::Segment::New(intptr_t size, Zone::Segment* next) { | 46 Zone::Segment* Zone::Segment::New(intptr_t size, Zone::Segment* next) { |
48 ASSERT(size >= 0); | 47 ASSERT(size >= 0); |
49 Segment* result = reinterpret_cast<Segment*>(malloc(size)); | 48 Segment* result = reinterpret_cast<Segment*>(malloc(size)); |
50 if (result == NULL) { | 49 if (result == NULL) { |
51 OUT_OF_MEMORY(); | 50 OUT_OF_MEMORY(); |
52 } | 51 } |
53 ASSERT(Utils::IsAligned(result->start(), Zone::kAlignment)); | 52 ASSERT(Utils::IsAligned(result->start(), Zone::kAlignment)); |
54 #ifdef DEBUG | 53 #ifdef DEBUG |
55 // Zap the entire allocated segment (including the header). | 54 // Zap the entire allocated segment (including the header). |
56 memset(result, kZapUninitializedByte, size); | 55 memset(result, kZapUninitializedByte, size); |
57 #endif | 56 #endif |
58 result->next_ = next; | 57 result->next_ = next; |
59 result->size_ = size; | 58 result->size_ = size; |
60 IncrementMemoryCapacity(size); | 59 IncrementMemoryCapacity(size); |
61 return result; | 60 return result; |
62 } | 61 } |
63 | 62 |
64 | |
65 void Zone::Segment::DeleteSegmentList(Segment* head) { | 63 void Zone::Segment::DeleteSegmentList(Segment* head) { |
66 Segment* current = head; | 64 Segment* current = head; |
67 while (current != NULL) { | 65 while (current != NULL) { |
68 DecrementMemoryCapacity(current->size()); | 66 DecrementMemoryCapacity(current->size()); |
69 Segment* next = current->next(); | 67 Segment* next = current->next(); |
70 #ifdef DEBUG | 68 #ifdef DEBUG |
71 // Zap the entire current segment (including the header). | 69 // Zap the entire current segment (including the header). |
72 memset(current, kZapDeletedByte, current->size()); | 70 memset(current, kZapDeletedByte, current->size()); |
73 #endif | 71 #endif |
74 Segment::Delete(current); | 72 Segment::Delete(current); |
75 current = next; | 73 current = next; |
76 } | 74 } |
77 } | 75 } |
78 | 76 |
79 | |
80 void Zone::Segment::IncrementMemoryCapacity(uintptr_t size) { | 77 void Zone::Segment::IncrementMemoryCapacity(uintptr_t size) { |
81 Thread* current_thread = Thread::Current(); | 78 Thread* current_thread = Thread::Current(); |
82 if (current_thread != NULL) { | 79 if (current_thread != NULL) { |
83 current_thread->IncrementMemoryCapacity(size); | 80 current_thread->IncrementMemoryCapacity(size); |
84 } else if (ApiNativeScope::Current() != NULL) { | 81 } else if (ApiNativeScope::Current() != NULL) { |
85 // If there is no current thread, we might be inside of a native scope. | 82 // If there is no current thread, we might be inside of a native scope. |
86 ApiNativeScope::IncrementNativeScopeMemoryCapacity(size); | 83 ApiNativeScope::IncrementNativeScopeMemoryCapacity(size); |
87 } | 84 } |
88 } | 85 } |
89 | 86 |
90 | |
91 void Zone::Segment::DecrementMemoryCapacity(uintptr_t size) { | 87 void Zone::Segment::DecrementMemoryCapacity(uintptr_t size) { |
92 Thread* current_thread = Thread::Current(); | 88 Thread* current_thread = Thread::Current(); |
93 if (current_thread != NULL) { | 89 if (current_thread != NULL) { |
94 current_thread->DecrementMemoryCapacity(size); | 90 current_thread->DecrementMemoryCapacity(size); |
95 } else if (ApiNativeScope::Current() != NULL) { | 91 } else if (ApiNativeScope::Current() != NULL) { |
96 // If there is no current thread, we might be inside of a native scope. | 92 // If there is no current thread, we might be inside of a native scope. |
97 ApiNativeScope::DecrementNativeScopeMemoryCapacity(size); | 93 ApiNativeScope::DecrementNativeScopeMemoryCapacity(size); |
98 } | 94 } |
99 } | 95 } |
100 | 96 |
101 | |
102 // TODO(bkonyi): We need to account for the initial chunk size when a new zone | 97 // TODO(bkonyi): We need to account for the initial chunk size when a new zone |
103 // is created within a new thread or ApiNativeScope when calculating high | 98 // is created within a new thread or ApiNativeScope when calculating high |
104 // watermarks or memory consumption. | 99 // watermarks or memory consumption. |
105 Zone::Zone() | 100 Zone::Zone() |
106 : initial_buffer_(buffer_, kInitialChunkSize), | 101 : initial_buffer_(buffer_, kInitialChunkSize), |
107 position_(initial_buffer_.start()), | 102 position_(initial_buffer_.start()), |
108 limit_(initial_buffer_.end()), | 103 limit_(initial_buffer_.end()), |
109 head_(NULL), | 104 head_(NULL), |
110 large_segments_(NULL), | 105 large_segments_(NULL), |
111 handles_(), | 106 handles_(), |
112 previous_(NULL) { | 107 previous_(NULL) { |
113 ASSERT(Utils::IsAligned(position_, kAlignment)); | 108 ASSERT(Utils::IsAligned(position_, kAlignment)); |
114 Segment::IncrementMemoryCapacity(kInitialChunkSize); | 109 Segment::IncrementMemoryCapacity(kInitialChunkSize); |
115 #ifdef DEBUG | 110 #ifdef DEBUG |
116 // Zap the entire initial buffer. | 111 // Zap the entire initial buffer. |
117 memset(initial_buffer_.pointer(), kZapUninitializedByte, | 112 memset(initial_buffer_.pointer(), kZapUninitializedByte, |
118 initial_buffer_.size()); | 113 initial_buffer_.size()); |
119 #endif | 114 #endif |
120 } | 115 } |
121 | 116 |
122 | |
123 Zone::~Zone() { | 117 Zone::~Zone() { |
124 if (FLAG_trace_zones) { | 118 if (FLAG_trace_zones) { |
125 DumpZoneSizes(); | 119 DumpZoneSizes(); |
126 } | 120 } |
127 DeleteAll(); | 121 DeleteAll(); |
128 Segment::DecrementMemoryCapacity(kInitialChunkSize); | 122 Segment::DecrementMemoryCapacity(kInitialChunkSize); |
129 } | 123 } |
130 | 124 |
131 | |
132 void Zone::DeleteAll() { | 125 void Zone::DeleteAll() { |
133 // Traverse the chained list of segments, zapping (in debug mode) | 126 // Traverse the chained list of segments, zapping (in debug mode) |
134 // and freeing every zone segment. | 127 // and freeing every zone segment. |
135 if (head_ != NULL) { | 128 if (head_ != NULL) { |
136 Segment::DeleteSegmentList(head_); | 129 Segment::DeleteSegmentList(head_); |
137 } | 130 } |
138 if (large_segments_ != NULL) { | 131 if (large_segments_ != NULL) { |
139 Segment::DeleteSegmentList(large_segments_); | 132 Segment::DeleteSegmentList(large_segments_); |
140 } | 133 } |
141 // Reset zone state. | 134 // Reset zone state. |
142 #ifdef DEBUG | 135 #ifdef DEBUG |
143 memset(initial_buffer_.pointer(), kZapDeletedByte, initial_buffer_.size()); | 136 memset(initial_buffer_.pointer(), kZapDeletedByte, initial_buffer_.size()); |
144 #endif | 137 #endif |
145 position_ = initial_buffer_.start(); | 138 position_ = initial_buffer_.start(); |
146 limit_ = initial_buffer_.end(); | 139 limit_ = initial_buffer_.end(); |
147 head_ = NULL; | 140 head_ = NULL; |
148 large_segments_ = NULL; | 141 large_segments_ = NULL; |
149 previous_ = NULL; | 142 previous_ = NULL; |
150 handles_.Reset(); | 143 handles_.Reset(); |
151 } | 144 } |
152 | 145 |
153 | |
154 uintptr_t Zone::SizeInBytes() const { | 146 uintptr_t Zone::SizeInBytes() const { |
155 uintptr_t size = 0; | 147 uintptr_t size = 0; |
156 for (Segment* s = large_segments_; s != NULL; s = s->next()) { | 148 for (Segment* s = large_segments_; s != NULL; s = s->next()) { |
157 size += s->size(); | 149 size += s->size(); |
158 } | 150 } |
159 if (head_ == NULL) { | 151 if (head_ == NULL) { |
160 return size + (position_ - initial_buffer_.start()); | 152 return size + (position_ - initial_buffer_.start()); |
161 } | 153 } |
162 size += initial_buffer_.size(); | 154 size += initial_buffer_.size(); |
163 for (Segment* s = head_->next(); s != NULL; s = s->next()) { | 155 for (Segment* s = head_->next(); s != NULL; s = s->next()) { |
164 size += s->size(); | 156 size += s->size(); |
165 } | 157 } |
166 return size + (position_ - head_->start()); | 158 return size + (position_ - head_->start()); |
167 } | 159 } |
168 | 160 |
169 | |
170 uintptr_t Zone::CapacityInBytes() const { | 161 uintptr_t Zone::CapacityInBytes() const { |
171 uintptr_t size = 0; | 162 uintptr_t size = 0; |
172 for (Segment* s = large_segments_; s != NULL; s = s->next()) { | 163 for (Segment* s = large_segments_; s != NULL; s = s->next()) { |
173 size += s->size(); | 164 size += s->size(); |
174 } | 165 } |
175 if (head_ == NULL) { | 166 if (head_ == NULL) { |
176 return size + initial_buffer_.size(); | 167 return size + initial_buffer_.size(); |
177 } | 168 } |
178 size += initial_buffer_.size(); | 169 size += initial_buffer_.size(); |
179 for (Segment* s = head_; s != NULL; s = s->next()) { | 170 for (Segment* s = head_; s != NULL; s = s->next()) { |
180 size += s->size(); | 171 size += s->size(); |
181 } | 172 } |
182 return size; | 173 return size; |
183 } | 174 } |
184 | 175 |
185 | |
186 uword Zone::AllocateExpand(intptr_t size) { | 176 uword Zone::AllocateExpand(intptr_t size) { |
187 ASSERT(size >= 0); | 177 ASSERT(size >= 0); |
188 if (FLAG_trace_zones) { | 178 if (FLAG_trace_zones) { |
189 OS::PrintErr("*** Expanding zone 0x%" Px "\n", | 179 OS::PrintErr("*** Expanding zone 0x%" Px "\n", |
190 reinterpret_cast<intptr_t>(this)); | 180 reinterpret_cast<intptr_t>(this)); |
191 DumpZoneSizes(); | 181 DumpZoneSizes(); |
192 } | 182 } |
193 // Make sure the requested size is already properly aligned and that | 183 // Make sure the requested size is already properly aligned and that |
194 // there isn't enough room in the Zone to satisfy the request. | 184 // there isn't enough room in the Zone to satisfy the request. |
195 ASSERT(Utils::IsAligned(size, kAlignment)); | 185 ASSERT(Utils::IsAligned(size, kAlignment)); |
(...skipping 12 matching lines...) Expand all Loading... |
208 head_ = Segment::New(kSegmentSize, head_); | 198 head_ = Segment::New(kSegmentSize, head_); |
209 | 199 |
210 // Recompute 'position' and 'limit' based on the new head segment. | 200 // Recompute 'position' and 'limit' based on the new head segment. |
211 uword result = Utils::RoundUp(head_->start(), kAlignment); | 201 uword result = Utils::RoundUp(head_->start(), kAlignment); |
212 position_ = result + size; | 202 position_ = result + size; |
213 limit_ = head_->end(); | 203 limit_ = head_->end(); |
214 ASSERT(position_ <= limit_); | 204 ASSERT(position_ <= limit_); |
215 return result; | 205 return result; |
216 } | 206 } |
217 | 207 |
218 | |
219 uword Zone::AllocateLargeSegment(intptr_t size) { | 208 uword Zone::AllocateLargeSegment(intptr_t size) { |
220 ASSERT(size >= 0); | 209 ASSERT(size >= 0); |
221 // Make sure the requested size is already properly aligned and that | 210 // Make sure the requested size is already properly aligned and that |
222 // there isn't enough room in the Zone to satisfy the request. | 211 // there isn't enough room in the Zone to satisfy the request. |
223 ASSERT(Utils::IsAligned(size, kAlignment)); | 212 ASSERT(Utils::IsAligned(size, kAlignment)); |
224 intptr_t free_size = (limit_ - position_); | 213 intptr_t free_size = (limit_ - position_); |
225 ASSERT(free_size < size); | 214 ASSERT(free_size < size); |
226 | 215 |
227 // Create a new large segment and chain it up. | 216 // Create a new large segment and chain it up. |
228 ASSERT(Utils::IsAligned(sizeof(Segment), kAlignment)); | 217 ASSERT(Utils::IsAligned(sizeof(Segment), kAlignment)); |
229 size += sizeof(Segment); // Account for book keeping fields in size. | 218 size += sizeof(Segment); // Account for book keeping fields in size. |
230 large_segments_ = Segment::New(size, large_segments_); | 219 large_segments_ = Segment::New(size, large_segments_); |
231 | 220 |
232 uword result = Utils::RoundUp(large_segments_->start(), kAlignment); | 221 uword result = Utils::RoundUp(large_segments_->start(), kAlignment); |
233 return result; | 222 return result; |
234 } | 223 } |
235 | 224 |
236 | |
237 char* Zone::MakeCopyOfString(const char* str) { | 225 char* Zone::MakeCopyOfString(const char* str) { |
238 intptr_t len = strlen(str) + 1; // '\0'-terminated. | 226 intptr_t len = strlen(str) + 1; // '\0'-terminated. |
239 char* copy = Alloc<char>(len); | 227 char* copy = Alloc<char>(len); |
240 strncpy(copy, str, len); | 228 strncpy(copy, str, len); |
241 return copy; | 229 return copy; |
242 } | 230 } |
243 | 231 |
244 | |
245 char* Zone::MakeCopyOfStringN(const char* str, intptr_t len) { | 232 char* Zone::MakeCopyOfStringN(const char* str, intptr_t len) { |
246 ASSERT(len >= 0); | 233 ASSERT(len >= 0); |
247 for (intptr_t i = 0; i < len; i++) { | 234 for (intptr_t i = 0; i < len; i++) { |
248 if (str[i] == '\0') { | 235 if (str[i] == '\0') { |
249 len = i; | 236 len = i; |
250 break; | 237 break; |
251 } | 238 } |
252 } | 239 } |
253 char* copy = Alloc<char>(len + 1); // +1 for '\0' | 240 char* copy = Alloc<char>(len + 1); // +1 for '\0' |
254 strncpy(copy, str, len); | 241 strncpy(copy, str, len); |
255 copy[len] = '\0'; | 242 copy[len] = '\0'; |
256 return copy; | 243 return copy; |
257 } | 244 } |
258 | 245 |
259 | |
260 char* Zone::ConcatStrings(const char* a, const char* b, char join) { | 246 char* Zone::ConcatStrings(const char* a, const char* b, char join) { |
261 intptr_t a_len = (a == NULL) ? 0 : strlen(a); | 247 intptr_t a_len = (a == NULL) ? 0 : strlen(a); |
262 const intptr_t b_len = strlen(b) + 1; // '\0'-terminated. | 248 const intptr_t b_len = strlen(b) + 1; // '\0'-terminated. |
263 const intptr_t len = a_len + b_len; | 249 const intptr_t len = a_len + b_len; |
264 char* copy = Alloc<char>(len); | 250 char* copy = Alloc<char>(len); |
265 if (a_len > 0) { | 251 if (a_len > 0) { |
266 strncpy(copy, a, a_len); | 252 strncpy(copy, a, a_len); |
267 // Insert join character. | 253 // Insert join character. |
268 copy[a_len++] = join; | 254 copy[a_len++] = join; |
269 } | 255 } |
270 strncpy(©[a_len], b, b_len); | 256 strncpy(©[a_len], b, b_len); |
271 return copy; | 257 return copy; |
272 } | 258 } |
273 | 259 |
274 | |
275 void Zone::DumpZoneSizes() { | 260 void Zone::DumpZoneSizes() { |
276 intptr_t size = 0; | 261 intptr_t size = 0; |
277 for (Segment* s = large_segments_; s != NULL; s = s->next()) { | 262 for (Segment* s = large_segments_; s != NULL; s = s->next()) { |
278 size += s->size(); | 263 size += s->size(); |
279 } | 264 } |
280 OS::PrintErr("*** Zone(0x%" Px | 265 OS::PrintErr("*** Zone(0x%" Px |
281 ") size in bytes," | 266 ") size in bytes," |
282 " Total = %" Pd " Large Segments = %" Pd "\n", | 267 " Total = %" Pd " Large Segments = %" Pd "\n", |
283 reinterpret_cast<intptr_t>(this), SizeInBytes(), size); | 268 reinterpret_cast<intptr_t>(this), SizeInBytes(), size); |
284 } | 269 } |
285 | 270 |
286 | |
287 void Zone::VisitObjectPointers(ObjectPointerVisitor* visitor) { | 271 void Zone::VisitObjectPointers(ObjectPointerVisitor* visitor) { |
288 Zone* zone = this; | 272 Zone* zone = this; |
289 while (zone != NULL) { | 273 while (zone != NULL) { |
290 zone->handles()->VisitObjectPointers(visitor); | 274 zone->handles()->VisitObjectPointers(visitor); |
291 zone = zone->previous_; | 275 zone = zone->previous_; |
292 } | 276 } |
293 } | 277 } |
294 | 278 |
295 | |
296 char* Zone::PrintToString(const char* format, ...) { | 279 char* Zone::PrintToString(const char* format, ...) { |
297 va_list args; | 280 va_list args; |
298 va_start(args, format); | 281 va_start(args, format); |
299 char* buffer = OS::VSCreate(this, format, args); | 282 char* buffer = OS::VSCreate(this, format, args); |
300 va_end(args); | 283 va_end(args); |
301 return buffer; | 284 return buffer; |
302 } | 285 } |
303 | 286 |
304 | |
305 char* Zone::VPrint(const char* format, va_list args) { | 287 char* Zone::VPrint(const char* format, va_list args) { |
306 return OS::VSCreate(this, format, args); | 288 return OS::VSCreate(this, format, args); |
307 } | 289 } |
308 | 290 |
309 | |
310 StackZone::StackZone(Thread* thread) : StackResource(thread), zone_() { | 291 StackZone::StackZone(Thread* thread) : StackResource(thread), zone_() { |
311 if (FLAG_trace_zones) { | 292 if (FLAG_trace_zones) { |
312 OS::PrintErr("*** Starting a new Stack zone 0x%" Px "(0x%" Px ")\n", | 293 OS::PrintErr("*** Starting a new Stack zone 0x%" Px "(0x%" Px ")\n", |
313 reinterpret_cast<intptr_t>(this), | 294 reinterpret_cast<intptr_t>(this), |
314 reinterpret_cast<intptr_t>(&zone_)); | 295 reinterpret_cast<intptr_t>(&zone_)); |
315 } | 296 } |
316 zone_.Link(thread->zone()); | 297 zone_.Link(thread->zone()); |
317 thread->set_zone(&zone_); | 298 thread->set_zone(&zone_); |
318 } | 299 } |
319 | 300 |
320 | |
321 StackZone::~StackZone() { | 301 StackZone::~StackZone() { |
322 ASSERT(thread()->zone() == &zone_); | 302 ASSERT(thread()->zone() == &zone_); |
323 thread()->set_zone(zone_.previous_); | 303 thread()->set_zone(zone_.previous_); |
324 if (FLAG_trace_zones) { | 304 if (FLAG_trace_zones) { |
325 OS::PrintErr("*** Deleting Stack zone 0x%" Px "(0x%" Px ")\n", | 305 OS::PrintErr("*** Deleting Stack zone 0x%" Px "(0x%" Px ")\n", |
326 reinterpret_cast<intptr_t>(this), | 306 reinterpret_cast<intptr_t>(this), |
327 reinterpret_cast<intptr_t>(&zone_)); | 307 reinterpret_cast<intptr_t>(&zone_)); |
328 } | 308 } |
329 } | 309 } |
330 | 310 |
331 } // namespace dart | 311 } // namespace dart |
OLD | NEW |