| 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 10 matching lines...) Expand all Loading... |
| 21 public: | 21 public: |
| 22 Segment* next() const { return next_; } | 22 Segment* next() const { return next_; } |
| 23 intptr_t size() const { return size_; } | 23 intptr_t size() const { return size_; } |
| 24 | 24 |
| 25 uword start() { return address(sizeof(Segment)); } | 25 uword start() { return address(sizeof(Segment)); } |
| 26 uword end() { return address(size_); } | 26 uword end() { return address(size_); } |
| 27 | 27 |
| 28 // Allocate or delete individual segments. | 28 // Allocate or delete individual segments. |
| 29 static Segment* New(intptr_t size, Segment* next); | 29 static Segment* New(intptr_t size, Segment* next); |
| 30 static void DeleteSegmentList(Segment* segment); | 30 static void DeleteSegmentList(Segment* segment); |
| 31 static void IncrementMemoryCapacity(uintptr_t size); |
| 32 static void DecrementMemoryCapacity(uintptr_t size); |
| 31 | 33 |
| 32 private: | 34 private: |
| 33 Segment* next_; | 35 Segment* next_; |
| 34 intptr_t size_; | 36 intptr_t size_; |
| 35 | 37 |
| 36 // Computes the address of the nth byte in this segment. | 38 // Computes the address of the nth byte in this segment. |
| 37 uword address(int n) { return reinterpret_cast<uword>(this) + n; } | 39 uword address(int n) { return reinterpret_cast<uword>(this) + n; } |
| 38 | 40 |
| 39 static void Delete(Segment* segment) { free(segment); } | 41 static void Delete(Segment* segment) { free(segment); } |
| 40 | 42 |
| 41 DISALLOW_IMPLICIT_CONSTRUCTORS(Segment); | 43 DISALLOW_IMPLICIT_CONSTRUCTORS(Segment); |
| 42 }; | 44 }; |
| 43 | 45 |
| 44 | 46 |
| 47 Zone::Segment* Zone::Segment::New(intptr_t size, Zone::Segment* next) { |
| 48 ASSERT(size >= 0); |
| 49 Segment* result = reinterpret_cast<Segment*>(malloc(size)); |
| 50 if (result == NULL) { |
| 51 OUT_OF_MEMORY(); |
| 52 } |
| 53 ASSERT(Utils::IsAligned(result->start(), Zone::kAlignment)); |
| 54 #ifdef DEBUG |
| 55 // Zap the entire allocated segment (including the header). |
| 56 memset(result, kZapUninitializedByte, size); |
| 57 #endif |
| 58 result->next_ = next; |
| 59 result->size_ = size; |
| 60 IncrementMemoryCapacity(size); |
| 61 return result; |
| 62 } |
| 63 |
| 64 |
| 45 void Zone::Segment::DeleteSegmentList(Segment* head) { | 65 void Zone::Segment::DeleteSegmentList(Segment* head) { |
| 46 Segment* current = head; | 66 Segment* current = head; |
| 47 Thread* current_thread = Thread::Current(); | |
| 48 while (current != NULL) { | 67 while (current != NULL) { |
| 49 if (current_thread != NULL) { | 68 DecrementMemoryCapacity(current->size()); |
| 50 current_thread->DecrementMemoryUsage(current->size()); | |
| 51 } else if (ApiNativeScope::Current() != NULL) { | |
| 52 // If there is no current thread, we might be inside of a native scope. | |
| 53 ApiNativeScope::DecrementNativeScopeMemoryUsage(current->size()); | |
| 54 } | |
| 55 Segment* next = current->next(); | 69 Segment* next = current->next(); |
| 56 #ifdef DEBUG | 70 #ifdef DEBUG |
| 57 // Zap the entire current segment (including the header). | 71 // Zap the entire current segment (including the header). |
| 58 memset(current, kZapDeletedByte, current->size()); | 72 memset(current, kZapDeletedByte, current->size()); |
| 59 #endif | 73 #endif |
| 60 Segment::Delete(current); | 74 Segment::Delete(current); |
| 61 current = next; | 75 current = next; |
| 62 } | 76 } |
| 63 } | 77 } |
| 64 | 78 |
| 65 | 79 |
| 66 Zone::Segment* Zone::Segment::New(intptr_t size, Zone::Segment* next) { | 80 void Zone::Segment::IncrementMemoryCapacity(uintptr_t size) { |
| 67 ASSERT(size >= 0); | 81 Thread* current_thread = Thread::Current(); |
| 68 Segment* result = reinterpret_cast<Segment*>(malloc(size)); | 82 if (current_thread != NULL) { |
| 69 if (result == NULL) { | 83 current_thread->IncrementMemoryCapacity(size); |
| 70 OUT_OF_MEMORY(); | |
| 71 } | |
| 72 ASSERT(Utils::IsAligned(result->start(), Zone::kAlignment)); | |
| 73 #ifdef DEBUG | |
| 74 // Zap the entire allocated segment (including the header). | |
| 75 memset(result, kZapUninitializedByte, size); | |
| 76 #endif | |
| 77 result->next_ = next; | |
| 78 result->size_ = size; | |
| 79 Thread* current = Thread::Current(); | |
| 80 if (current != NULL) { | |
| 81 current->IncrementMemoryUsage(size); | |
| 82 } else if (ApiNativeScope::Current() != NULL) { | 84 } else if (ApiNativeScope::Current() != NULL) { |
| 83 // If there is no current thread, we might be inside of a native scope. | 85 // If there is no current thread, we might be inside of a native scope. |
| 84 ApiNativeScope::IncrementNativeScopeMemoryUsage(size); | 86 ApiNativeScope::IncrementNativeScopeMemoryCapacity(size); |
| 85 } | 87 } |
| 86 return result; | |
| 87 } | 88 } |
| 88 | 89 |
| 90 |
| 91 void Zone::Segment::DecrementMemoryCapacity(uintptr_t size) { |
| 92 Thread* current_thread = Thread::Current(); |
| 93 if (current_thread != NULL) { |
| 94 current_thread->DecrementMemoryCapacity(size); |
| 95 } else if (ApiNativeScope::Current() != NULL) { |
| 96 // If there is no current thread, we might be inside of a native scope. |
| 97 ApiNativeScope::DecrementNativeScopeMemoryCapacity(size); |
| 98 } |
| 99 } |
| 100 |
| 101 |
| 89 // TODO(bkonyi): We need to account for the initial chunk size when a new zone | 102 // 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 | 103 // is created within a new thread or ApiNativeScope when calculating high |
| 91 // watermarks or memory consumption. | 104 // watermarks or memory consumption. |
| 92 Zone::Zone() | 105 Zone::Zone() |
| 93 : initial_buffer_(buffer_, kInitialChunkSize), | 106 : initial_buffer_(buffer_, kInitialChunkSize), |
| 94 position_(initial_buffer_.start()), | 107 position_(initial_buffer_.start()), |
| 95 limit_(initial_buffer_.end()), | 108 limit_(initial_buffer_.end()), |
| 96 head_(NULL), | 109 head_(NULL), |
| 97 large_segments_(NULL), | 110 large_segments_(NULL), |
| 98 handles_(), | 111 handles_(), |
| 99 previous_(NULL) { | 112 previous_(NULL) { |
| 100 ASSERT(Utils::IsAligned(position_, kAlignment)); | 113 ASSERT(Utils::IsAligned(position_, kAlignment)); |
| 101 Thread* current = Thread::Current(); | 114 Segment::IncrementMemoryCapacity(kInitialChunkSize); |
| 102 if (current != NULL) { | |
| 103 current->IncrementMemoryUsage(kInitialChunkSize); | |
| 104 } | |
| 105 #ifdef DEBUG | 115 #ifdef DEBUG |
| 106 // Zap the entire initial buffer. | 116 // Zap the entire initial buffer. |
| 107 memset(initial_buffer_.pointer(), kZapUninitializedByte, | 117 memset(initial_buffer_.pointer(), kZapUninitializedByte, |
| 108 initial_buffer_.size()); | 118 initial_buffer_.size()); |
| 109 #endif | 119 #endif |
| 110 } | 120 } |
| 111 | 121 |
| 112 | 122 |
| 113 Zone::~Zone() { | 123 Zone::~Zone() { |
| 114 if (FLAG_trace_zones) { | 124 if (FLAG_trace_zones) { |
| 115 DumpZoneSizes(); | 125 DumpZoneSizes(); |
| 116 } | 126 } |
| 117 Thread* current = Thread::Current(); | |
| 118 if (current != NULL) { | |
| 119 current->DecrementMemoryUsage(kInitialChunkSize); | |
| 120 } | |
| 121 DeleteAll(); | 127 DeleteAll(); |
| 128 Segment::DecrementMemoryCapacity(kInitialChunkSize); |
| 122 } | 129 } |
| 123 | 130 |
| 124 | 131 |
| 125 void Zone::DeleteAll() { | 132 void Zone::DeleteAll() { |
| 126 // Traverse the chained list of segments, zapping (in debug mode) | 133 // Traverse the chained list of segments, zapping (in debug mode) |
| 127 // and freeing every zone segment. | 134 // and freeing every zone segment. |
| 128 if (head_ != NULL) { | 135 if (head_ != NULL) { |
| 129 Segment::DeleteSegmentList(head_); | 136 Segment::DeleteSegmentList(head_); |
| 130 } | 137 } |
| 131 if (large_segments_ != NULL) { | 138 if (large_segments_ != NULL) { |
| 132 Segment::DeleteSegmentList(large_segments_); | 139 Segment::DeleteSegmentList(large_segments_); |
| 133 } | 140 } |
| 134 // Reset zone state. | 141 // Reset zone state. |
| 135 #ifdef DEBUG | 142 #ifdef DEBUG |
| 136 memset(initial_buffer_.pointer(), kZapDeletedByte, initial_buffer_.size()); | 143 memset(initial_buffer_.pointer(), kZapDeletedByte, initial_buffer_.size()); |
| 137 #endif | 144 #endif |
| 138 position_ = initial_buffer_.start(); | 145 position_ = initial_buffer_.start(); |
| 139 limit_ = initial_buffer_.end(); | 146 limit_ = initial_buffer_.end(); |
| 140 head_ = NULL; | 147 head_ = NULL; |
| 141 large_segments_ = NULL; | 148 large_segments_ = NULL; |
| 142 previous_ = NULL; | 149 previous_ = NULL; |
| 143 handles_.Reset(); | 150 handles_.Reset(); |
| 144 } | 151 } |
| 145 | 152 |
| 146 | 153 |
| 147 intptr_t Zone::SizeInBytes() const { | 154 uintptr_t Zone::SizeInBytes() const { |
| 148 intptr_t size = 0; | 155 uintptr_t size = 0; |
| 149 for (Segment* s = large_segments_; s != NULL; s = s->next()) { | 156 for (Segment* s = large_segments_; s != NULL; s = s->next()) { |
| 150 size += s->size(); | 157 size += s->size(); |
| 151 } | 158 } |
| 152 if (head_ == NULL) { | 159 if (head_ == NULL) { |
| 153 return size + (position_ - initial_buffer_.start()); | 160 return size + (position_ - initial_buffer_.start()); |
| 154 } | 161 } |
| 155 size += initial_buffer_.size(); | 162 size += initial_buffer_.size(); |
| 156 for (Segment* s = head_->next(); s != NULL; s = s->next()) { | 163 for (Segment* s = head_->next(); s != NULL; s = s->next()) { |
| 157 size += s->size(); | 164 size += s->size(); |
| 158 } | 165 } |
| 159 return size + (position_ - head_->start()); | 166 return size + (position_ - head_->start()); |
| 160 } | 167 } |
| 161 | 168 |
| 162 | 169 |
| 163 intptr_t Zone::CapacityInBytes() const { | 170 uintptr_t Zone::CapacityInBytes() const { |
| 164 intptr_t size = 0; | 171 uintptr_t size = 0; |
| 165 for (Segment* s = large_segments_; s != NULL; s = s->next()) { | 172 for (Segment* s = large_segments_; s != NULL; s = s->next()) { |
| 166 size += s->size(); | 173 size += s->size(); |
| 167 } | 174 } |
| 168 if (head_ == NULL) { | 175 if (head_ == NULL) { |
| 169 return size + initial_buffer_.size(); | 176 return size + initial_buffer_.size(); |
| 170 } | 177 } |
| 171 size += initial_buffer_.size(); | 178 size += initial_buffer_.size(); |
| 172 for (Segment* s = head_; s != NULL; s = s->next()) { | 179 for (Segment* s = head_; s != NULL; s = s->next()) { |
| 173 size += s->size(); | 180 size += s->size(); |
| 174 } | 181 } |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 293 va_end(args); | 300 va_end(args); |
| 294 return buffer; | 301 return buffer; |
| 295 } | 302 } |
| 296 | 303 |
| 297 | 304 |
| 298 char* Zone::VPrint(const char* format, va_list args) { | 305 char* Zone::VPrint(const char* format, va_list args) { |
| 299 return OS::VSCreate(this, format, args); | 306 return OS::VSCreate(this, format, args); |
| 300 } | 307 } |
| 301 | 308 |
| 302 | 309 |
| 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_() { | 310 StackZone::StackZone(Thread* thread) : StackResource(thread), zone_() { |
| 317 if (FLAG_trace_zones) { | 311 if (FLAG_trace_zones) { |
| 318 OS::PrintErr("*** Starting a new Stack zone 0x%" Px "(0x%" Px ")\n", | 312 OS::PrintErr("*** Starting a new Stack zone 0x%" Px "(0x%" Px ")\n", |
| 319 reinterpret_cast<intptr_t>(this), | 313 reinterpret_cast<intptr_t>(this), |
| 320 reinterpret_cast<intptr_t>(&zone_)); | 314 reinterpret_cast<intptr_t>(&zone_)); |
| 321 } | 315 } |
| 322 zone_.Link(thread->zone()); | 316 zone_.Link(thread->zone()); |
| 323 thread->set_zone(&zone_); | 317 thread->set_zone(&zone_); |
| 324 } | 318 } |
| 325 | 319 |
| 326 | 320 |
| 327 StackZone::~StackZone() { | 321 StackZone::~StackZone() { |
| 328 ASSERT(thread()->zone() == &zone_); | 322 ASSERT(thread()->zone() == &zone_); |
| 329 thread()->set_zone(zone_.previous_); | 323 thread()->set_zone(zone_.previous_); |
| 330 if (FLAG_trace_zones) { | 324 if (FLAG_trace_zones) { |
| 331 OS::PrintErr("*** Deleting Stack zone 0x%" Px "(0x%" Px ")\n", | 325 OS::PrintErr("*** Deleting Stack zone 0x%" Px "(0x%" Px ")\n", |
| 332 reinterpret_cast<intptr_t>(this), | 326 reinterpret_cast<intptr_t>(this), |
| 333 reinterpret_cast<intptr_t>(&zone_)); | 327 reinterpret_cast<intptr_t>(&zone_)); |
| 334 } | 328 } |
| 335 } | 329 } |
| 336 | 330 |
| 337 } // namespace dart | 331 } // namespace dart |
| OLD | NEW |