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 |