| OLD | NEW |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, 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/freelist.h" | 5 #include "vm/freelist.h" |
| 6 | 6 |
| 7 #include "vm/bit_set.h" | 7 #include "vm/bit_set.h" |
| 8 #include "vm/hash_map.h" | 8 #include "vm/hash_map.h" |
| 9 #include "vm/lockers.h" | 9 #include "vm/lockers.h" |
| 10 #include "vm/object.h" | 10 #include "vm/object.h" |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 70 uword FreeList::TryAllocateLocked(intptr_t size, bool is_protected) { | 70 uword FreeList::TryAllocateLocked(intptr_t size, bool is_protected) { |
| 71 DEBUG_ASSERT(mutex_->IsOwnedByCurrentThread()); | 71 DEBUG_ASSERT(mutex_->IsOwnedByCurrentThread()); |
| 72 // Precondition: is_protected is false or else all free list elements are | 72 // Precondition: is_protected is false or else all free list elements are |
| 73 // in non-writable pages. | 73 // in non-writable pages. |
| 74 | 74 |
| 75 // Postcondition: if allocation succeeds, the allocated block is writable. | 75 // Postcondition: if allocation succeeds, the allocated block is writable. |
| 76 int index = IndexForSize(size); | 76 int index = IndexForSize(size); |
| 77 if ((index != kNumLists) && free_map_.Test(index)) { | 77 if ((index != kNumLists) && free_map_.Test(index)) { |
| 78 FreeListElement* element = DequeueElement(index); | 78 FreeListElement* element = DequeueElement(index); |
| 79 if (is_protected) { | 79 if (is_protected) { |
| 80 bool status = | 80 bool status = VirtualMemory::Protect(reinterpret_cast<void*>(element), |
| 81 VirtualMemory::Protect(reinterpret_cast<void*>(element), | 81 size, VirtualMemory::kReadWrite); |
| 82 size, | |
| 83 VirtualMemory::kReadWrite); | |
| 84 ASSERT(status); | 82 ASSERT(status); |
| 85 } | 83 } |
| 86 return reinterpret_cast<uword>(element); | 84 return reinterpret_cast<uword>(element); |
| 87 } | 85 } |
| 88 | 86 |
| 89 if ((index + 1) < kNumLists) { | 87 if ((index + 1) < kNumLists) { |
| 90 intptr_t next_index = free_map_.Next(index + 1); | 88 intptr_t next_index = free_map_.Next(index + 1); |
| 91 if (next_index != -1) { | 89 if (next_index != -1) { |
| 92 // Dequeue an element from the list, split and enqueue the remainder in | 90 // Dequeue an element from the list, split and enqueue the remainder in |
| 93 // the appropriate list. | 91 // the appropriate list. |
| 94 FreeListElement* element = DequeueElement(next_index); | 92 FreeListElement* element = DequeueElement(next_index); |
| 95 if (is_protected) { | 93 if (is_protected) { |
| 96 // Make the allocated block and the header of the remainder element | 94 // Make the allocated block and the header of the remainder element |
| 97 // writable. The remainder will be non-writable if necessary after | 95 // writable. The remainder will be non-writable if necessary after |
| 98 // the call to SplitElementAfterAndEnqueue. | 96 // the call to SplitElementAfterAndEnqueue. |
| 99 // If the remainder size is zero, only the element itself needs to | 97 // If the remainder size is zero, only the element itself needs to |
| 100 // be made writable. | 98 // be made writable. |
| 101 intptr_t remainder_size = element->Size() - size; | 99 intptr_t remainder_size = element->Size() - size; |
| 102 intptr_t region_size = | 100 intptr_t region_size = |
| 103 size + FreeListElement::HeaderSizeFor(remainder_size); | 101 size + FreeListElement::HeaderSizeFor(remainder_size); |
| 104 bool status = | 102 bool status = |
| 105 VirtualMemory::Protect(reinterpret_cast<void*>(element), | 103 VirtualMemory::Protect(reinterpret_cast<void*>(element), |
| 106 region_size, | 104 region_size, VirtualMemory::kReadWrite); |
| 107 VirtualMemory::kReadWrite); | |
| 108 ASSERT(status); | 105 ASSERT(status); |
| 109 } | 106 } |
| 110 SplitElementAfterAndEnqueue(element, size, is_protected); | 107 SplitElementAfterAndEnqueue(element, size, is_protected); |
| 111 return reinterpret_cast<uword>(element); | 108 return reinterpret_cast<uword>(element); |
| 112 } | 109 } |
| 113 } | 110 } |
| 114 | 111 |
| 115 FreeListElement* previous = NULL; | 112 FreeListElement* previous = NULL; |
| 116 FreeListElement* current = free_lists_[kNumLists]; | 113 FreeListElement* current = free_lists_[kNumLists]; |
| 117 while (current != NULL) { | 114 while (current != NULL) { |
| 118 if (current->Size() >= size) { | 115 if (current->Size() >= size) { |
| 119 // Found an element large enough to hold the requested size. Dequeue, | 116 // Found an element large enough to hold the requested size. Dequeue, |
| 120 // split and enqueue the remainder. | 117 // split and enqueue the remainder. |
| 121 intptr_t remainder_size = current->Size() - size; | 118 intptr_t remainder_size = current->Size() - size; |
| 122 intptr_t region_size = | 119 intptr_t region_size = |
| 123 size + FreeListElement::HeaderSizeFor(remainder_size); | 120 size + FreeListElement::HeaderSizeFor(remainder_size); |
| 124 if (is_protected) { | 121 if (is_protected) { |
| 125 // Make the allocated block and the header of the remainder element | 122 // Make the allocated block and the header of the remainder element |
| 126 // writable. The remainder will be non-writable if necessary after | 123 // writable. The remainder will be non-writable if necessary after |
| 127 // the call to SplitElementAfterAndEnqueue. | 124 // the call to SplitElementAfterAndEnqueue. |
| 128 bool status = | 125 bool status = |
| 129 VirtualMemory::Protect(reinterpret_cast<void*>(current), | 126 VirtualMemory::Protect(reinterpret_cast<void*>(current), |
| 130 region_size, | 127 region_size, VirtualMemory::kReadWrite); |
| 131 VirtualMemory::kReadWrite); | |
| 132 ASSERT(status); | 128 ASSERT(status); |
| 133 } | 129 } |
| 134 | 130 |
| 135 if (previous == NULL) { | 131 if (previous == NULL) { |
| 136 free_lists_[kNumLists] = current->next(); | 132 free_lists_[kNumLists] = current->next(); |
| 137 } else { | 133 } else { |
| 138 // If the previous free list element's next field is protected, it | 134 // If the previous free list element's next field is protected, it |
| 139 // needs to be unprotected before storing to it and reprotected | 135 // needs to be unprotected before storing to it and reprotected |
| 140 // after. | 136 // after. |
| 141 bool target_is_protected = false; | 137 bool target_is_protected = false; |
| 142 uword target_address = 0L; | 138 uword target_address = 0L; |
| 143 if (is_protected) { | 139 if (is_protected) { |
| 144 uword writable_start = reinterpret_cast<uword>(current); | 140 uword writable_start = reinterpret_cast<uword>(current); |
| 145 uword writable_end = writable_start + region_size - 1; | 141 uword writable_end = writable_start + region_size - 1; |
| 146 target_address = previous->next_address(); | 142 target_address = previous->next_address(); |
| 147 target_is_protected = | 143 target_is_protected = |
| 148 !VirtualMemory::InSamePage(target_address, writable_start) && | 144 !VirtualMemory::InSamePage(target_address, writable_start) && |
| 149 !VirtualMemory::InSamePage(target_address, writable_end); | 145 !VirtualMemory::InSamePage(target_address, writable_end); |
| 150 } | 146 } |
| 151 if (target_is_protected) { | 147 if (target_is_protected) { |
| 152 bool status = | 148 bool status = |
| 153 VirtualMemory::Protect(reinterpret_cast<void*>(target_address), | 149 VirtualMemory::Protect(reinterpret_cast<void*>(target_address), |
| 154 kWordSize, | 150 kWordSize, VirtualMemory::kReadWrite); |
| 155 VirtualMemory::kReadWrite); | |
| 156 ASSERT(status); | 151 ASSERT(status); |
| 157 } | 152 } |
| 158 previous->set_next(current->next()); | 153 previous->set_next(current->next()); |
| 159 if (target_is_protected) { | 154 if (target_is_protected) { |
| 160 bool status = | 155 bool status = |
| 161 VirtualMemory::Protect(reinterpret_cast<void*>(target_address), | 156 VirtualMemory::Protect(reinterpret_cast<void*>(target_address), |
| 162 kWordSize, | 157 kWordSize, VirtualMemory::kReadExecute); |
| 163 VirtualMemory::kReadExecute); | |
| 164 ASSERT(status); | 158 ASSERT(status); |
| 165 } | 159 } |
| 166 } | 160 } |
| 167 SplitElementAfterAndEnqueue(current, size, is_protected); | 161 SplitElementAfterAndEnqueue(current, size, is_protected); |
| 168 return reinterpret_cast<uword>(current); | 162 return reinterpret_cast<uword>(current); |
| 169 } | 163 } |
| 170 previous = current; | 164 previous = current; |
| 171 current = current->next(); | 165 current = current->next(); |
| 172 } | 166 } |
| 173 return 0; | 167 return 0; |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 213 index = kNumLists; | 207 index = kNumLists; |
| 214 } | 208 } |
| 215 return index; | 209 return index; |
| 216 } | 210 } |
| 217 | 211 |
| 218 | 212 |
| 219 void FreeList::EnqueueElement(FreeListElement* element, intptr_t index) { | 213 void FreeList::EnqueueElement(FreeListElement* element, intptr_t index) { |
| 220 FreeListElement* next = free_lists_[index]; | 214 FreeListElement* next = free_lists_[index]; |
| 221 if (next == NULL && index != kNumLists) { | 215 if (next == NULL && index != kNumLists) { |
| 222 free_map_.Set(index, true); | 216 free_map_.Set(index, true); |
| 223 last_free_small_size_ = Utils::Maximum(last_free_small_size_, | 217 last_free_small_size_ = |
| 224 index << kObjectAlignmentLog2); | 218 Utils::Maximum(last_free_small_size_, index << kObjectAlignmentLog2); |
| 225 } | 219 } |
| 226 element->set_next(next); | 220 element->set_next(next); |
| 227 free_lists_[index] = element; | 221 free_lists_[index] = element; |
| 228 } | 222 } |
| 229 | 223 |
| 230 | 224 |
| 231 FreeListElement* FreeList::DequeueElement(intptr_t index) { | 225 FreeListElement* FreeList::DequeueElement(intptr_t index) { |
| 232 FreeListElement* result = free_lists_[index]; | 226 FreeListElement* result = free_lists_[index]; |
| 233 FreeListElement* next = result->next(); | 227 FreeListElement* next = result->next(); |
| 234 if (next == NULL && index != kNumLists) { | 228 if (next == NULL && index != kNumLists) { |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 266 intptr_t small_bytes = 0; | 260 intptr_t small_bytes = 0; |
| 267 for (int i = 0; i < kNumLists; ++i) { | 261 for (int i = 0; i < kNumLists; ++i) { |
| 268 if (free_lists_[i] == NULL) { | 262 if (free_lists_[i] == NULL) { |
| 269 continue; | 263 continue; |
| 270 } | 264 } |
| 271 small_sizes += 1; | 265 small_sizes += 1; |
| 272 intptr_t list_length = LengthLocked(i); | 266 intptr_t list_length = LengthLocked(i); |
| 273 small_objects += list_length; | 267 small_objects += list_length; |
| 274 intptr_t list_bytes = list_length * i * kObjectAlignment; | 268 intptr_t list_bytes = list_length * i * kObjectAlignment; |
| 275 small_bytes += list_bytes; | 269 small_bytes += list_bytes; |
| 276 OS::Print("small %3d [%8d bytes] : " | 270 OS::Print( |
| 277 "%8" Pd " objs; %8.1f KB; %8.1f cum KB\n", | 271 "small %3d [%8d bytes] : " |
| 278 i, | 272 "%8" Pd " objs; %8.1f KB; %8.1f cum KB\n", |
| 279 i * kObjectAlignment, | 273 i, i * kObjectAlignment, list_length, |
| 280 list_length, | 274 list_bytes / static_cast<double>(KB), |
| 281 list_bytes / static_cast<double>(KB), | 275 small_bytes / static_cast<double>(KB)); |
| 282 small_bytes / static_cast<double>(KB)); | |
| 283 } | 276 } |
| 284 } | 277 } |
| 285 | 278 |
| 286 | 279 |
| 287 class IntptrPair { | 280 class IntptrPair { |
| 288 public: | 281 public: |
| 289 IntptrPair() : first_(-1), second_(-1) {} | 282 IntptrPair() : first_(-1), second_(-1) {} |
| 290 IntptrPair(intptr_t first, intptr_t second) | 283 IntptrPair(intptr_t first, intptr_t second) |
| 291 : first_(first), second_(second) {} | 284 : first_(first), second_(second) {} |
| 292 | 285 |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 326 } | 319 } |
| 327 | 320 |
| 328 MallocDirectChainedHashMap<NumbersKeyValueTrait<IntptrPair> >::Iterator it = | 321 MallocDirectChainedHashMap<NumbersKeyValueTrait<IntptrPair> >::Iterator it = |
| 329 map.GetIterator(); | 322 map.GetIterator(); |
| 330 IntptrPair* pair; | 323 IntptrPair* pair; |
| 331 while ((pair = it.Next()) != NULL) { | 324 while ((pair = it.Next()) != NULL) { |
| 332 intptr_t size = pair->first(); | 325 intptr_t size = pair->first(); |
| 333 intptr_t list_length = pair->second(); | 326 intptr_t list_length = pair->second(); |
| 334 intptr_t list_bytes = list_length * size; | 327 intptr_t list_bytes = list_length * size; |
| 335 large_bytes += list_bytes; | 328 large_bytes += list_bytes; |
| 336 OS::Print("large %3" Pd " [%8" Pd " bytes] : " | 329 OS::Print("large %3" Pd " [%8" Pd |
| 330 " bytes] : " |
| 337 "%8" Pd " objs; %8.1f KB; %8.1f cum KB\n", | 331 "%8" Pd " objs; %8.1f KB; %8.1f cum KB\n", |
| 338 size / kObjectAlignment, | 332 size / kObjectAlignment, size, list_length, |
| 339 size, | |
| 340 list_length, | |
| 341 list_bytes / static_cast<double>(KB), | 333 list_bytes / static_cast<double>(KB), |
| 342 large_bytes / static_cast<double>(KB)); | 334 large_bytes / static_cast<double>(KB)); |
| 343 } | 335 } |
| 344 } | 336 } |
| 345 | 337 |
| 346 | 338 |
| 347 void FreeList::Print() const { | 339 void FreeList::Print() const { |
| 348 MutexLocker ml(mutex_); | 340 MutexLocker ml(mutex_); |
| 349 PrintSmall(); | 341 PrintSmall(); |
| 350 PrintLarge(); | 342 PrintLarge(); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 366 EnqueueElement(element, remainder_index); | 358 EnqueueElement(element, remainder_index); |
| 367 | 359 |
| 368 // Postcondition: when allocating in a protected page, the remainder | 360 // Postcondition: when allocating in a protected page, the remainder |
| 369 // element is no longer writable unless it is in the same page as the | 361 // element is no longer writable unless it is in the same page as the |
| 370 // allocated element. (The allocated element is still writable, and the | 362 // allocated element. (The allocated element is still writable, and the |
| 371 // remainder element will be protected when the allocated one is). | 363 // remainder element will be protected when the allocated one is). |
| 372 if (is_protected && | 364 if (is_protected && |
| 373 !VirtualMemory::InSamePage(remainder_address - 1, remainder_address)) { | 365 !VirtualMemory::InSamePage(remainder_address - 1, remainder_address)) { |
| 374 bool status = | 366 bool status = |
| 375 VirtualMemory::Protect(reinterpret_cast<void*>(remainder_address), | 367 VirtualMemory::Protect(reinterpret_cast<void*>(remainder_address), |
| 376 remainder_size, | 368 remainder_size, VirtualMemory::kReadExecute); |
| 377 VirtualMemory::kReadExecute); | |
| 378 ASSERT(status); | 369 ASSERT(status); |
| 379 } | 370 } |
| 380 } | 371 } |
| 381 | 372 |
| 382 | 373 |
| 383 FreeListElement* FreeList::TryAllocateLarge(intptr_t minimum_size) { | 374 FreeListElement* FreeList::TryAllocateLarge(intptr_t minimum_size) { |
| 384 MutexLocker ml(mutex_); | 375 MutexLocker ml(mutex_); |
| 385 return TryAllocateLargeLocked(minimum_size); | 376 return TryAllocateLargeLocked(minimum_size); |
| 386 } | 377 } |
| 387 | 378 |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 422 if (next_index != -1) { | 413 if (next_index != -1) { |
| 423 FreeListElement* element = DequeueElement(next_index); | 414 FreeListElement* element = DequeueElement(next_index); |
| 424 SplitElementAfterAndEnqueue(element, size, false); | 415 SplitElementAfterAndEnqueue(element, size, false); |
| 425 return reinterpret_cast<uword>(element); | 416 return reinterpret_cast<uword>(element); |
| 426 } | 417 } |
| 427 } | 418 } |
| 428 return 0; | 419 return 0; |
| 429 } | 420 } |
| 430 | 421 |
| 431 } // namespace dart | 422 } // namespace dart |
| OLD | NEW |