| 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 |