Chromium Code Reviews| 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 29 matching lines...) Expand all Loading... | |
| 40 | 40 |
| 41 DISALLOW_IMPLICIT_CONSTRUCTORS(Segment); | 41 DISALLOW_IMPLICIT_CONSTRUCTORS(Segment); |
| 42 }; | 42 }; |
| 43 | 43 |
| 44 | 44 |
| 45 void Zone::Segment::DeleteSegmentList(Segment* head) { | 45 void Zone::Segment::DeleteSegmentList(Segment* head) { |
| 46 Segment* current = head; | 46 Segment* current = head; |
| 47 Thread* current_thread = Thread::Current(); | 47 Thread* current_thread = Thread::Current(); |
| 48 while (current != NULL) { | 48 while (current != NULL) { |
| 49 if (current_thread != NULL) { | 49 if (current_thread != NULL) { |
| 50 current_thread->DecrementMemoryUsage(current->size()); | 50 current_thread->DecrementMemoryCapacity(current->size()); |
|
Cutch
2017/03/22 17:21:49
ditto here:
IncrementThreadMemoryCapacity / Decre
bkonyi
2017/03/22 18:01:48
Done.
| |
| 51 } else if (ApiNativeScope::Current() != NULL) { | 51 } else if (ApiNativeScope::Current() != NULL) { |
| 52 // If there is no current thread, we might be inside of a native scope. | 52 // If there is no current thread, we might be inside of a native scope. |
| 53 ApiNativeScope::DecrementNativeScopeMemoryUsage(current->size()); | 53 ApiNativeScope::DecrementNativeScopeMemoryCapacity(current->size()); |
| 54 } | 54 } |
| 55 Segment* next = current->next(); | 55 Segment* next = current->next(); |
| 56 #ifdef DEBUG | 56 #ifdef DEBUG |
| 57 // Zap the entire current segment (including the header). | 57 // Zap the entire current segment (including the header). |
| 58 memset(current, kZapDeletedByte, current->size()); | 58 memset(current, kZapDeletedByte, current->size()); |
| 59 #endif | 59 #endif |
| 60 Segment::Delete(current); | 60 Segment::Delete(current); |
| 61 current = next; | 61 current = next; |
| 62 } | 62 } |
| 63 } | 63 } |
| 64 | 64 |
| 65 | 65 |
| 66 Zone::Segment* Zone::Segment::New(intptr_t size, Zone::Segment* next) { | 66 Zone::Segment* Zone::Segment::New(intptr_t size, Zone::Segment* next) { |
| 67 ASSERT(size >= 0); | 67 ASSERT(size >= 0); |
| 68 Segment* result = reinterpret_cast<Segment*>(malloc(size)); | 68 Segment* result = reinterpret_cast<Segment*>(malloc(size)); |
| 69 if (result == NULL) { | 69 if (result == NULL) { |
| 70 OUT_OF_MEMORY(); | 70 OUT_OF_MEMORY(); |
| 71 } | 71 } |
| 72 ASSERT(Utils::IsAligned(result->start(), Zone::kAlignment)); | 72 ASSERT(Utils::IsAligned(result->start(), Zone::kAlignment)); |
| 73 #ifdef DEBUG | 73 #ifdef DEBUG |
| 74 // Zap the entire allocated segment (including the header). | 74 // Zap the entire allocated segment (including the header). |
| 75 memset(result, kZapUninitializedByte, size); | 75 memset(result, kZapUninitializedByte, size); |
| 76 #endif | 76 #endif |
| 77 result->next_ = next; | 77 result->next_ = next; |
| 78 result->size_ = size; | 78 result->size_ = size; |
| 79 Thread* current = Thread::Current(); | 79 Thread* current_thread = Thread::Current(); |
| 80 if (current != NULL) { | 80 if (current_thread != NULL) { |
| 81 current->IncrementMemoryUsage(size); | 81 current_thread->IncrementMemoryCapacity(size); |
| 82 } else if (ApiNativeScope::Current() != NULL) { | 82 } else if (ApiNativeScope::Current() != NULL) { |
| 83 // If there is no current thread, we might be inside of a native scope. | 83 // If there is no current thread, we might be inside of a native scope. |
| 84 ApiNativeScope::IncrementNativeScopeMemoryUsage(size); | 84 ApiNativeScope::IncrementNativeScopeMemoryCapacity(size); |
| 85 } | 85 } |
| 86 return result; | 86 return result; |
| 87 } | 87 } |
| 88 | 88 |
| 89 // TODO(bkonyi): We need to account for the initial chunk size when a new zone | 89 // TODO(bkonyi): We need to account for the initial chunk size when a new zone |
| 90 // is created within a new thread or ApiNativeScope when calculating high | 90 // is created within a new thread or ApiNativeScope when calculating high |
| 91 // watermarks or memory consumption. | 91 // watermarks or memory consumption. |
| 92 Zone::Zone() | 92 Zone::Zone() |
| 93 : initial_buffer_(buffer_, kInitialChunkSize), | 93 : initial_buffer_(buffer_, kInitialChunkSize), |
| 94 position_(initial_buffer_.start()), | 94 position_(initial_buffer_.start()), |
| 95 limit_(initial_buffer_.end()), | 95 limit_(initial_buffer_.end()), |
| 96 head_(NULL), | 96 head_(NULL), |
| 97 large_segments_(NULL), | 97 large_segments_(NULL), |
| 98 handles_(), | 98 handles_(), |
| 99 previous_(NULL) { | 99 previous_(NULL) { |
| 100 ASSERT(Utils::IsAligned(position_, kAlignment)); | 100 ASSERT(Utils::IsAligned(position_, kAlignment)); |
| 101 Thread* current = Thread::Current(); | 101 Thread* current_thread = Thread::Current(); |
| 102 if (current != NULL) { | 102 if (current_thread != NULL) { |
| 103 current->IncrementMemoryUsage(kInitialChunkSize); | 103 current_thread->IncrementMemoryCapacity(kInitialChunkSize); |
| 104 } | 104 } |
| 105 #ifdef DEBUG | 105 #ifdef DEBUG |
| 106 // Zap the entire initial buffer. | 106 // Zap the entire initial buffer. |
| 107 memset(initial_buffer_.pointer(), kZapUninitializedByte, | 107 memset(initial_buffer_.pointer(), kZapUninitializedByte, |
| 108 initial_buffer_.size()); | 108 initial_buffer_.size()); |
| 109 #endif | 109 #endif |
| 110 } | 110 } |
| 111 | 111 |
| 112 | 112 |
| 113 Zone::~Zone() { | 113 Zone::~Zone() { |
| 114 if (FLAG_trace_zones) { | 114 if (FLAG_trace_zones) { |
| 115 DumpZoneSizes(); | 115 DumpZoneSizes(); |
| 116 } | 116 } |
| 117 Thread* current = Thread::Current(); | 117 DeleteAll(); |
| 118 if (current != NULL) { | 118 |
| 119 current->DecrementMemoryUsage(kInitialChunkSize); | 119 Thread* current_thread = Thread::Current(); |
| 120 if (current_thread != NULL) { | |
| 121 current_thread->DecrementMemoryCapacity(kInitialChunkSize); | |
| 120 } | 122 } |
| 121 DeleteAll(); | |
| 122 } | 123 } |
| 123 | 124 |
| 124 | 125 |
| 125 void Zone::DeleteAll() { | 126 void Zone::DeleteAll() { |
| 127 Thread* current_thread = Thread::Current(); | |
| 128 if (current_thread != NULL) { | |
| 129 current_thread->DecrementMemoryUsage(SizeInBytes()); | |
| 130 } | |
| 126 // Traverse the chained list of segments, zapping (in debug mode) | 131 // Traverse the chained list of segments, zapping (in debug mode) |
| 127 // and freeing every zone segment. | 132 // and freeing every zone segment. |
| 128 if (head_ != NULL) { | 133 if (head_ != NULL) { |
| 129 Segment::DeleteSegmentList(head_); | 134 Segment::DeleteSegmentList(head_); |
| 130 } | 135 } |
| 131 if (large_segments_ != NULL) { | 136 if (large_segments_ != NULL) { |
| 132 Segment::DeleteSegmentList(large_segments_); | 137 Segment::DeleteSegmentList(large_segments_); |
| 133 } | 138 } |
| 134 // Reset zone state. | 139 // Reset zone state. |
| 135 #ifdef DEBUG | 140 #ifdef DEBUG |
| 136 memset(initial_buffer_.pointer(), kZapDeletedByte, initial_buffer_.size()); | 141 memset(initial_buffer_.pointer(), kZapDeletedByte, initial_buffer_.size()); |
| 137 #endif | 142 #endif |
| 138 position_ = initial_buffer_.start(); | 143 position_ = initial_buffer_.start(); |
| 139 limit_ = initial_buffer_.end(); | 144 limit_ = initial_buffer_.end(); |
| 140 head_ = NULL; | 145 head_ = NULL; |
| 141 large_segments_ = NULL; | 146 large_segments_ = NULL; |
| 142 previous_ = NULL; | 147 previous_ = NULL; |
| 143 handles_.Reset(); | 148 handles_.Reset(); |
| 144 } | 149 } |
| 145 | 150 |
| 146 | 151 |
| 147 intptr_t Zone::SizeInBytes() const { | 152 uintptr_t Zone::SizeInBytes() const { |
| 148 intptr_t size = 0; | 153 uintptr_t size = 0; |
| 149 for (Segment* s = large_segments_; s != NULL; s = s->next()) { | 154 for (Segment* s = large_segments_; s != NULL; s = s->next()) { |
| 150 size += s->size(); | 155 size += s->size(); |
| 151 } | 156 } |
| 152 if (head_ == NULL) { | 157 if (head_ == NULL) { |
| 153 return size + (position_ - initial_buffer_.start()); | 158 return size + (position_ - initial_buffer_.start()); |
| 154 } | 159 } |
| 155 size += initial_buffer_.size(); | 160 size += initial_buffer_.size(); |
| 156 for (Segment* s = head_->next(); s != NULL; s = s->next()) { | 161 for (Segment* s = head_->next(); s != NULL; s = s->next()) { |
| 157 size += s->size(); | 162 size += s->size(); |
| 158 } | 163 } |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 169 return size + initial_buffer_.size(); | 174 return size + initial_buffer_.size(); |
| 170 } | 175 } |
| 171 size += initial_buffer_.size(); | 176 size += initial_buffer_.size(); |
| 172 for (Segment* s = head_; s != NULL; s = s->next()) { | 177 for (Segment* s = head_; s != NULL; s = s->next()) { |
| 173 size += s->size(); | 178 size += s->size(); |
| 174 } | 179 } |
| 175 return size; | 180 return size; |
| 176 } | 181 } |
| 177 | 182 |
| 178 | 183 |
| 184 intptr_t Zone::FreeCapacityInBytes() const { | |
| 185 if (head_ == NULL) { | |
| 186 return initial_buffer_.start() + initial_buffer_.size() - position_; | |
| 187 } else { | |
| 188 return head_->start() + head_->size() - position_; | |
| 189 } | |
| 190 } | |
| 191 | |
| 192 | |
| 179 uword Zone::AllocateExpand(intptr_t size) { | 193 uword Zone::AllocateExpand(intptr_t size) { |
| 180 ASSERT(size >= 0); | 194 ASSERT(size >= 0); |
| 181 if (FLAG_trace_zones) { | 195 if (FLAG_trace_zones) { |
| 182 OS::PrintErr("*** Expanding zone 0x%" Px "\n", | 196 OS::PrintErr("*** Expanding zone 0x%" Px "\n", |
| 183 reinterpret_cast<intptr_t>(this)); | 197 reinterpret_cast<intptr_t>(this)); |
| 184 DumpZoneSizes(); | 198 DumpZoneSizes(); |
| 185 } | 199 } |
| 186 // Make sure the requested size is already properly aligned and that | 200 // Make sure the requested size is already properly aligned and that |
| 187 // there isn't enough room in the Zone to satisfy the request. | 201 // there isn't enough room in the Zone to satisfy the request. |
| 188 ASSERT(Utils::IsAligned(size, kAlignment)); | 202 ASSERT(Utils::IsAligned(size, kAlignment)); |
| 189 intptr_t free_size = (limit_ - position_); | 203 intptr_t free_size = (limit_ - position_); |
| 190 ASSERT(free_size < size); | 204 ASSERT(free_size < size); |
| 191 | 205 |
| 192 // First check to see if we should just chain it as a large segment. | 206 // First check to see if we should just chain it as a large segment. |
| 193 intptr_t max_size = | 207 intptr_t max_size = |
| 194 Utils::RoundDown(kSegmentSize - sizeof(Segment), kAlignment); | 208 Utils::RoundDown(kSegmentSize - sizeof(Segment), kAlignment); |
| 195 ASSERT(max_size > 0); | 209 ASSERT(max_size > 0); |
| 196 if (size > max_size) { | 210 if (size > max_size) { |
| 197 return AllocateLargeSegment(size); | 211 return AllocateLargeSegment(size); |
| 198 } | 212 } |
| 199 | 213 |
| 214 intptr_t remaining_capacity = FreeCapacityInBytes(); | |
| 215 | |
| 200 // Allocate another segment and chain it up. | 216 // Allocate another segment and chain it up. |
| 201 head_ = Segment::New(kSegmentSize, head_); | 217 head_ = Segment::New(kSegmentSize, head_); |
| 202 | 218 |
| 219 Thread* current_thread = Thread::Current(); | |
| 220 if (current_thread != NULL) { | |
| 221 current_thread->IncrementMemoryUsage(remaining_capacity + size); | |
| 222 } | |
| 223 | |
| 203 // Recompute 'position' and 'limit' based on the new head segment. | 224 // Recompute 'position' and 'limit' based on the new head segment. |
| 204 uword result = Utils::RoundUp(head_->start(), kAlignment); | 225 uword result = Utils::RoundUp(head_->start(), kAlignment); |
| 205 position_ = result + size; | 226 position_ = result + size; |
| 206 limit_ = head_->end(); | 227 limit_ = head_->end(); |
| 207 ASSERT(position_ <= limit_); | 228 ASSERT(position_ <= limit_); |
| 208 return result; | 229 return result; |
| 209 } | 230 } |
| 210 | 231 |
| 211 | 232 |
| 212 uword Zone::AllocateLargeSegment(intptr_t size) { | 233 uword Zone::AllocateLargeSegment(intptr_t size) { |
| 213 ASSERT(size >= 0); | 234 ASSERT(size >= 0); |
| 214 // Make sure the requested size is already properly aligned and that | 235 // Make sure the requested size is already properly aligned and that |
| 215 // there isn't enough room in the Zone to satisfy the request. | 236 // there isn't enough room in the Zone to satisfy the request. |
| 216 ASSERT(Utils::IsAligned(size, kAlignment)); | 237 ASSERT(Utils::IsAligned(size, kAlignment)); |
| 217 intptr_t free_size = (limit_ - position_); | 238 intptr_t free_size = (limit_ - position_); |
| 218 ASSERT(free_size < size); | 239 ASSERT(free_size < size); |
| 219 | 240 |
| 220 // Create a new large segment and chain it up. | 241 // Create a new large segment and chain it up. |
| 221 ASSERT(Utils::IsAligned(sizeof(Segment), kAlignment)); | 242 ASSERT(Utils::IsAligned(sizeof(Segment), kAlignment)); |
| 222 size += sizeof(Segment); // Account for book keeping fields in size. | 243 size += sizeof(Segment); // Account for book keeping fields in size. |
| 223 large_segments_ = Segment::New(size, large_segments_); | 244 large_segments_ = Segment::New(size, large_segments_); |
| 224 | 245 |
| 246 Thread* current_thread = Thread::Current(); | |
| 247 if (current_thread != NULL) { | |
| 248 current_thread->IncrementMemoryUsage(size); | |
| 249 } | |
| 250 | |
| 225 uword result = Utils::RoundUp(large_segments_->start(), kAlignment); | 251 uword result = Utils::RoundUp(large_segments_->start(), kAlignment); |
| 226 return result; | 252 return result; |
| 227 } | 253 } |
| 228 | 254 |
| 229 | 255 |
| 230 char* Zone::MakeCopyOfString(const char* str) { | 256 char* Zone::MakeCopyOfString(const char* str) { |
| 231 intptr_t len = strlen(str) + 1; // '\0'-terminated. | 257 intptr_t len = strlen(str) + 1; // '\0'-terminated. |
| 232 char* copy = Alloc<char>(len); | 258 char* copy = Alloc<char>(len); |
| 233 strncpy(copy, str, len); | 259 strncpy(copy, str, len); |
| 234 return copy; | 260 return copy; |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 293 va_end(args); | 319 va_end(args); |
| 294 return buffer; | 320 return buffer; |
| 295 } | 321 } |
| 296 | 322 |
| 297 | 323 |
| 298 char* Zone::VPrint(const char* format, va_list args) { | 324 char* Zone::VPrint(const char* format, va_list args) { |
| 299 return OS::VSCreate(this, format, args); | 325 return OS::VSCreate(this, format, args); |
| 300 } | 326 } |
| 301 | 327 |
| 302 | 328 |
| 303 #ifndef PRODUCT | |
| 304 // TODO(bkonyi): Currently dead code. See issue #28885. | |
| 305 void Zone::PrintJSON(JSONStream* stream) const { | |
| 306 JSONObject jsobj(stream); | |
| 307 intptr_t capacity = CapacityInBytes(); | |
| 308 intptr_t used_size = SizeInBytes(); | |
| 309 jsobj.AddProperty("type", "_Zone"); | |
| 310 jsobj.AddProperty("capacity", capacity); | |
| 311 jsobj.AddProperty("used", used_size); | |
| 312 } | |
| 313 #endif | |
| 314 | |
| 315 | |
| 316 StackZone::StackZone(Thread* thread) : StackResource(thread), zone_() { | 329 StackZone::StackZone(Thread* thread) : StackResource(thread), zone_() { |
| 317 if (FLAG_trace_zones) { | 330 if (FLAG_trace_zones) { |
| 318 OS::PrintErr("*** Starting a new Stack zone 0x%" Px "(0x%" Px ")\n", | 331 OS::PrintErr("*** Starting a new Stack zone 0x%" Px "(0x%" Px ")\n", |
| 319 reinterpret_cast<intptr_t>(this), | 332 reinterpret_cast<intptr_t>(this), |
| 320 reinterpret_cast<intptr_t>(&zone_)); | 333 reinterpret_cast<intptr_t>(&zone_)); |
| 321 } | 334 } |
| 322 zone_.Link(thread->zone()); | 335 zone_.Link(thread->zone()); |
| 323 thread->set_zone(&zone_); | 336 thread->set_zone(&zone_); |
| 324 } | 337 } |
| 325 | 338 |
| 326 | 339 |
| 327 StackZone::~StackZone() { | 340 StackZone::~StackZone() { |
| 328 ASSERT(thread()->zone() == &zone_); | 341 ASSERT(thread()->zone() == &zone_); |
| 329 thread()->set_zone(zone_.previous_); | 342 thread()->set_zone(zone_.previous_); |
| 330 if (FLAG_trace_zones) { | 343 if (FLAG_trace_zones) { |
| 331 OS::PrintErr("*** Deleting Stack zone 0x%" Px "(0x%" Px ")\n", | 344 OS::PrintErr("*** Deleting Stack zone 0x%" Px "(0x%" Px ")\n", |
| 332 reinterpret_cast<intptr_t>(this), | 345 reinterpret_cast<intptr_t>(this), |
| 333 reinterpret_cast<intptr_t>(&zone_)); | 346 reinterpret_cast<intptr_t>(&zone_)); |
| 334 } | 347 } |
| 335 } | 348 } |
| 336 | 349 |
| 337 } // namespace dart | 350 } // namespace dart |
| OLD | NEW |