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" |
11 #include "vm/os_thread.h" | 11 #include "vm/os_thread.h" |
12 #include "vm/raw_object.h" | 12 #include "vm/raw_object.h" |
13 | 13 |
14 namespace dart { | 14 namespace dart { |
15 | 15 |
16 | |
17 FreeListElement* FreeListElement::AsElement(uword addr, intptr_t size) { | 16 FreeListElement* FreeListElement::AsElement(uword addr, intptr_t size) { |
18 // Precondition: the (page containing the) header of the element is | 17 // Precondition: the (page containing the) header of the element is |
19 // writable. | 18 // writable. |
20 ASSERT(size >= kObjectAlignment); | 19 ASSERT(size >= kObjectAlignment); |
21 ASSERT(Utils::IsAligned(size, kObjectAlignment)); | 20 ASSERT(Utils::IsAligned(size, kObjectAlignment)); |
22 | 21 |
23 FreeListElement* result = reinterpret_cast<FreeListElement*>(addr); | 22 FreeListElement* result = reinterpret_cast<FreeListElement*>(addr); |
24 | 23 |
25 uint32_t tags = 0; | 24 uint32_t tags = 0; |
26 tags = RawObject::SizeTag::update(size, tags); | 25 tags = RawObject::SizeTag::update(size, tags); |
27 tags = RawObject::ClassIdTag::update(kFreeListElement, tags); | 26 tags = RawObject::ClassIdTag::update(kFreeListElement, tags); |
28 // All words in a freelist element header should look like Smis. | 27 // All words in a freelist element header should look like Smis. |
29 ASSERT(!reinterpret_cast<RawObject*>(tags)->IsHeapObject()); | 28 ASSERT(!reinterpret_cast<RawObject*>(tags)->IsHeapObject()); |
30 | 29 |
31 result->tags_ = tags; | 30 result->tags_ = tags; |
32 #if defined(HASH_IN_OBJECT_HEADER) | 31 #if defined(HASH_IN_OBJECT_HEADER) |
33 // Clearing this is mostly for neatness. The identityHashCode | 32 // Clearing this is mostly for neatness. The identityHashCode |
34 // of free list entries is not used. | 33 // of free list entries is not used. |
35 result->hash_ = 0; | 34 result->hash_ = 0; |
36 #endif | 35 #endif |
37 if (size > RawObject::SizeTag::kMaxSizeTag) { | 36 if (size > RawObject::SizeTag::kMaxSizeTag) { |
38 *result->SizeAddress() = size; | 37 *result->SizeAddress() = size; |
39 } | 38 } |
40 result->set_next(NULL); | 39 result->set_next(NULL); |
41 return result; | 40 return result; |
42 // Postcondition: the (page containing the) header of the element is | 41 // Postcondition: the (page containing the) header of the element is |
43 // writable. | 42 // writable. |
44 } | 43 } |
45 | 44 |
46 | |
47 void FreeListElement::InitOnce() { | 45 void FreeListElement::InitOnce() { |
48 ASSERT(sizeof(FreeListElement) == kObjectAlignment); | 46 ASSERT(sizeof(FreeListElement) == kObjectAlignment); |
49 ASSERT(OFFSET_OF(FreeListElement, tags_) == Object::tags_offset()); | 47 ASSERT(OFFSET_OF(FreeListElement, tags_) == Object::tags_offset()); |
50 } | 48 } |
51 | 49 |
52 | |
53 intptr_t FreeListElement::HeaderSizeFor(intptr_t size) { | 50 intptr_t FreeListElement::HeaderSizeFor(intptr_t size) { |
54 if (size == 0) return 0; | 51 if (size == 0) return 0; |
55 return ((size > RawObject::SizeTag::kMaxSizeTag) ? 3 : 2) * kWordSize; | 52 return ((size > RawObject::SizeTag::kMaxSizeTag) ? 3 : 2) * kWordSize; |
56 } | 53 } |
57 | 54 |
58 | |
59 FreeList::FreeList() | 55 FreeList::FreeList() |
60 : mutex_(new Mutex()), | 56 : mutex_(new Mutex()), |
61 freelist_search_budget_(kInitialFreeListSearchBudget) { | 57 freelist_search_budget_(kInitialFreeListSearchBudget) { |
62 Reset(); | 58 Reset(); |
63 } | 59 } |
64 | 60 |
65 | |
66 FreeList::~FreeList() { | 61 FreeList::~FreeList() { |
67 delete mutex_; | 62 delete mutex_; |
68 } | 63 } |
69 | 64 |
70 | |
71 uword FreeList::TryAllocate(intptr_t size, bool is_protected) { | 65 uword FreeList::TryAllocate(intptr_t size, bool is_protected) { |
72 MutexLocker ml(mutex_); | 66 MutexLocker ml(mutex_); |
73 return TryAllocateLocked(size, is_protected); | 67 return TryAllocateLocked(size, is_protected); |
74 } | 68 } |
75 | 69 |
76 | |
77 uword FreeList::TryAllocateLocked(intptr_t size, bool is_protected) { | 70 uword FreeList::TryAllocateLocked(intptr_t size, bool is_protected) { |
78 DEBUG_ASSERT(mutex_->IsOwnedByCurrentThread()); | 71 DEBUG_ASSERT(mutex_->IsOwnedByCurrentThread()); |
79 // 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 |
80 // in non-writable pages. | 73 // in non-writable pages. |
81 | 74 |
82 // Postcondition: if allocation succeeds, the allocated block is writable. | 75 // Postcondition: if allocation succeeds, the allocated block is writable. |
83 int index = IndexForSize(size); | 76 int index = IndexForSize(size); |
84 if ((index != kNumLists) && free_map_.Test(index)) { | 77 if ((index != kNumLists) && free_map_.Test(index)) { |
85 FreeListElement* element = DequeueElement(index); | 78 FreeListElement* element = DequeueElement(index); |
86 if (is_protected) { | 79 if (is_protected) { |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
182 } else if (tries_left-- < 0) { | 175 } else if (tries_left-- < 0) { |
183 freelist_search_budget_ = kInitialFreeListSearchBudget; | 176 freelist_search_budget_ = kInitialFreeListSearchBudget; |
184 return 0; // Trigger allocation of new page. | 177 return 0; // Trigger allocation of new page. |
185 } | 178 } |
186 previous = current; | 179 previous = current; |
187 current = current->next(); | 180 current = current->next(); |
188 } | 181 } |
189 return 0; | 182 return 0; |
190 } | 183 } |
191 | 184 |
192 | |
193 void FreeList::Free(uword addr, intptr_t size) { | 185 void FreeList::Free(uword addr, intptr_t size) { |
194 MutexLocker ml(mutex_); | 186 MutexLocker ml(mutex_); |
195 FreeLocked(addr, size); | 187 FreeLocked(addr, size); |
196 } | 188 } |
197 | 189 |
198 | |
199 void FreeList::FreeLocked(uword addr, intptr_t size) { | 190 void FreeList::FreeLocked(uword addr, intptr_t size) { |
200 DEBUG_ASSERT(mutex_->IsOwnedByCurrentThread()); | 191 DEBUG_ASSERT(mutex_->IsOwnedByCurrentThread()); |
201 // Precondition required by AsElement and EnqueueElement: the (page | 192 // Precondition required by AsElement and EnqueueElement: the (page |
202 // containing the) header of the freed block should be writable. This is | 193 // containing the) header of the freed block should be writable. This is |
203 // the case when called for newly allocated pages because they are | 194 // the case when called for newly allocated pages because they are |
204 // allocated as writable. It is the case when called during GC sweeping | 195 // allocated as writable. It is the case when called during GC sweeping |
205 // because the entire heap is writable. | 196 // because the entire heap is writable. |
206 intptr_t index = IndexForSize(size); | 197 intptr_t index = IndexForSize(size); |
207 FreeListElement* element = FreeListElement::AsElement(addr, size); | 198 FreeListElement* element = FreeListElement::AsElement(addr, size); |
208 EnqueueElement(element, index); | 199 EnqueueElement(element, index); |
209 // Postcondition: the (page containing the) header is left writable. | 200 // Postcondition: the (page containing the) header is left writable. |
210 } | 201 } |
211 | 202 |
212 | |
213 void FreeList::Reset() { | 203 void FreeList::Reset() { |
214 MutexLocker ml(mutex_); | 204 MutexLocker ml(mutex_); |
215 free_map_.Reset(); | 205 free_map_.Reset(); |
216 last_free_small_size_ = -1; | 206 last_free_small_size_ = -1; |
217 for (int i = 0; i < (kNumLists + 1); i++) { | 207 for (int i = 0; i < (kNumLists + 1); i++) { |
218 free_lists_[i] = NULL; | 208 free_lists_[i] = NULL; |
219 } | 209 } |
220 } | 210 } |
221 | 211 |
222 | |
223 intptr_t FreeList::IndexForSize(intptr_t size) { | 212 intptr_t FreeList::IndexForSize(intptr_t size) { |
224 ASSERT(size >= kObjectAlignment); | 213 ASSERT(size >= kObjectAlignment); |
225 ASSERT(Utils::IsAligned(size, kObjectAlignment)); | 214 ASSERT(Utils::IsAligned(size, kObjectAlignment)); |
226 | 215 |
227 intptr_t index = size >> kObjectAlignmentLog2; | 216 intptr_t index = size >> kObjectAlignmentLog2; |
228 if (index >= kNumLists) { | 217 if (index >= kNumLists) { |
229 index = kNumLists; | 218 index = kNumLists; |
230 } | 219 } |
231 return index; | 220 return index; |
232 } | 221 } |
233 | 222 |
234 | |
235 void FreeList::EnqueueElement(FreeListElement* element, intptr_t index) { | 223 void FreeList::EnqueueElement(FreeListElement* element, intptr_t index) { |
236 FreeListElement* next = free_lists_[index]; | 224 FreeListElement* next = free_lists_[index]; |
237 if (next == NULL && index != kNumLists) { | 225 if (next == NULL && index != kNumLists) { |
238 free_map_.Set(index, true); | 226 free_map_.Set(index, true); |
239 last_free_small_size_ = | 227 last_free_small_size_ = |
240 Utils::Maximum(last_free_small_size_, index << kObjectAlignmentLog2); | 228 Utils::Maximum(last_free_small_size_, index << kObjectAlignmentLog2); |
241 } | 229 } |
242 element->set_next(next); | 230 element->set_next(next); |
243 free_lists_[index] = element; | 231 free_lists_[index] = element; |
244 } | 232 } |
245 | 233 |
246 | |
247 FreeListElement* FreeList::DequeueElement(intptr_t index) { | 234 FreeListElement* FreeList::DequeueElement(intptr_t index) { |
248 FreeListElement* result = free_lists_[index]; | 235 FreeListElement* result = free_lists_[index]; |
249 FreeListElement* next = result->next(); | 236 FreeListElement* next = result->next(); |
250 if (next == NULL && index != kNumLists) { | 237 if (next == NULL && index != kNumLists) { |
251 intptr_t size = index << kObjectAlignmentLog2; | 238 intptr_t size = index << kObjectAlignmentLog2; |
252 if (size == last_free_small_size_) { | 239 if (size == last_free_small_size_) { |
253 // Note: This is -1 * kObjectAlignment if no other small sizes remain. | 240 // Note: This is -1 * kObjectAlignment if no other small sizes remain. |
254 last_free_small_size_ = | 241 last_free_small_size_ = |
255 free_map_.ClearLastAndFindPrevious(index) * kObjectAlignment; | 242 free_map_.ClearLastAndFindPrevious(index) * kObjectAlignment; |
256 } else { | 243 } else { |
257 free_map_.Set(index, false); | 244 free_map_.Set(index, false); |
258 } | 245 } |
259 } | 246 } |
260 free_lists_[index] = next; | 247 free_lists_[index] = next; |
261 return result; | 248 return result; |
262 } | 249 } |
263 | 250 |
264 | |
265 intptr_t FreeList::LengthLocked(int index) const { | 251 intptr_t FreeList::LengthLocked(int index) const { |
266 DEBUG_ASSERT(mutex_->IsOwnedByCurrentThread()); | 252 DEBUG_ASSERT(mutex_->IsOwnedByCurrentThread()); |
267 ASSERT(index >= 0); | 253 ASSERT(index >= 0); |
268 ASSERT(index < kNumLists); | 254 ASSERT(index < kNumLists); |
269 intptr_t result = 0; | 255 intptr_t result = 0; |
270 FreeListElement* element = free_lists_[index]; | 256 FreeListElement* element = free_lists_[index]; |
271 while (element != NULL) { | 257 while (element != NULL) { |
272 ++result; | 258 ++result; |
273 element = element->next(); | 259 element = element->next(); |
274 } | 260 } |
275 return result; | 261 return result; |
276 } | 262 } |
277 | 263 |
278 | |
279 void FreeList::PrintSmall() const { | 264 void FreeList::PrintSmall() const { |
280 int small_sizes = 0; | 265 int small_sizes = 0; |
281 int small_objects = 0; | 266 int small_objects = 0; |
282 intptr_t small_bytes = 0; | 267 intptr_t small_bytes = 0; |
283 for (int i = 0; i < kNumLists; ++i) { | 268 for (int i = 0; i < kNumLists; ++i) { |
284 if (free_lists_[i] == NULL) { | 269 if (free_lists_[i] == NULL) { |
285 continue; | 270 continue; |
286 } | 271 } |
287 small_sizes += 1; | 272 small_sizes += 1; |
288 intptr_t list_length = LengthLocked(i); | 273 intptr_t list_length = LengthLocked(i); |
289 small_objects += list_length; | 274 small_objects += list_length; |
290 intptr_t list_bytes = list_length * i * kObjectAlignment; | 275 intptr_t list_bytes = list_length * i * kObjectAlignment; |
291 small_bytes += list_bytes; | 276 small_bytes += list_bytes; |
292 OS::Print( | 277 OS::Print( |
293 "small %3d [%8d bytes] : " | 278 "small %3d [%8d bytes] : " |
294 "%8" Pd " objs; %8.1f KB; %8.1f cum KB\n", | 279 "%8" Pd " objs; %8.1f KB; %8.1f cum KB\n", |
295 i, i * kObjectAlignment, list_length, | 280 i, i * kObjectAlignment, list_length, |
296 list_bytes / static_cast<double>(KB), | 281 list_bytes / static_cast<double>(KB), |
297 small_bytes / static_cast<double>(KB)); | 282 small_bytes / static_cast<double>(KB)); |
298 } | 283 } |
299 } | 284 } |
300 | 285 |
301 | |
302 class IntptrPair { | 286 class IntptrPair { |
303 public: | 287 public: |
304 IntptrPair() : first_(-1), second_(-1) {} | 288 IntptrPair() : first_(-1), second_(-1) {} |
305 IntptrPair(intptr_t first, intptr_t second) | 289 IntptrPair(intptr_t first, intptr_t second) |
306 : first_(first), second_(second) {} | 290 : first_(first), second_(second) {} |
307 | 291 |
308 intptr_t first() const { return first_; } | 292 intptr_t first() const { return first_; } |
309 intptr_t second() const { return second_; } | 293 intptr_t second() const { return second_; } |
310 void set_second(intptr_t s) { second_ = s; } | 294 void set_second(intptr_t s) { second_ = s; } |
311 | 295 |
312 bool operator==(const IntptrPair& other) { | 296 bool operator==(const IntptrPair& other) { |
313 return (first_ == other.first_) && (second_ == other.second_); | 297 return (first_ == other.first_) && (second_ == other.second_); |
314 } | 298 } |
315 | 299 |
316 bool operator!=(const IntptrPair& other) { | 300 bool operator!=(const IntptrPair& other) { |
317 return (first_ != other.first_) || (second_ != other.second_); | 301 return (first_ != other.first_) || (second_ != other.second_); |
318 } | 302 } |
319 | 303 |
320 private: | 304 private: |
321 intptr_t first_; | 305 intptr_t first_; |
322 intptr_t second_; | 306 intptr_t second_; |
323 }; | 307 }; |
324 | 308 |
325 | |
326 void FreeList::PrintLarge() const { | 309 void FreeList::PrintLarge() const { |
327 int large_sizes = 0; | 310 int large_sizes = 0; |
328 int large_objects = 0; | 311 int large_objects = 0; |
329 intptr_t large_bytes = 0; | 312 intptr_t large_bytes = 0; |
330 MallocDirectChainedHashMap<NumbersKeyValueTrait<IntptrPair> > map; | 313 MallocDirectChainedHashMap<NumbersKeyValueTrait<IntptrPair> > map; |
331 FreeListElement* node; | 314 FreeListElement* node; |
332 for (node = free_lists_[kNumLists]; node != NULL; node = node->next()) { | 315 for (node = free_lists_[kNumLists]; node != NULL; node = node->next()) { |
333 IntptrPair* pair = map.Lookup(node->Size()); | 316 IntptrPair* pair = map.Lookup(node->Size()); |
334 if (pair == NULL) { | 317 if (pair == NULL) { |
335 large_sizes += 1; | 318 large_sizes += 1; |
(...skipping 14 matching lines...) Expand all Loading... |
350 large_bytes += list_bytes; | 333 large_bytes += list_bytes; |
351 OS::Print("large %3" Pd " [%8" Pd | 334 OS::Print("large %3" Pd " [%8" Pd |
352 " bytes] : " | 335 " bytes] : " |
353 "%8" Pd " objs; %8.1f KB; %8.1f cum KB\n", | 336 "%8" Pd " objs; %8.1f KB; %8.1f cum KB\n", |
354 size / kObjectAlignment, size, list_length, | 337 size / kObjectAlignment, size, list_length, |
355 list_bytes / static_cast<double>(KB), | 338 list_bytes / static_cast<double>(KB), |
356 large_bytes / static_cast<double>(KB)); | 339 large_bytes / static_cast<double>(KB)); |
357 } | 340 } |
358 } | 341 } |
359 | 342 |
360 | |
361 void FreeList::Print() const { | 343 void FreeList::Print() const { |
362 MutexLocker ml(mutex_); | 344 MutexLocker ml(mutex_); |
363 PrintSmall(); | 345 PrintSmall(); |
364 PrintLarge(); | 346 PrintLarge(); |
365 } | 347 } |
366 | 348 |
367 | |
368 void FreeList::SplitElementAfterAndEnqueue(FreeListElement* element, | 349 void FreeList::SplitElementAfterAndEnqueue(FreeListElement* element, |
369 intptr_t size, | 350 intptr_t size, |
370 bool is_protected) { | 351 bool is_protected) { |
371 // Precondition required by AsElement and EnqueueElement: either | 352 // Precondition required by AsElement and EnqueueElement: either |
372 // element->Size() == size, or else the (page containing the) header of | 353 // element->Size() == size, or else the (page containing the) header of |
373 // the remainder element starting at element + size is writable. | 354 // the remainder element starting at element + size is writable. |
374 intptr_t remainder_size = element->Size() - size; | 355 intptr_t remainder_size = element->Size() - size; |
375 if (remainder_size == 0) return; | 356 if (remainder_size == 0) return; |
376 | 357 |
377 uword remainder_address = reinterpret_cast<uword>(element) + size; | 358 uword remainder_address = reinterpret_cast<uword>(element) + size; |
378 element = FreeListElement::AsElement(remainder_address, remainder_size); | 359 element = FreeListElement::AsElement(remainder_address, remainder_size); |
379 intptr_t remainder_index = IndexForSize(remainder_size); | 360 intptr_t remainder_index = IndexForSize(remainder_size); |
380 EnqueueElement(element, remainder_index); | 361 EnqueueElement(element, remainder_index); |
381 | 362 |
382 // Postcondition: when allocating in a protected page, the remainder | 363 // Postcondition: when allocating in a protected page, the remainder |
383 // element is no longer writable unless it is in the same page as the | 364 // element is no longer writable unless it is in the same page as the |
384 // allocated element. (The allocated element is still writable, and the | 365 // allocated element. (The allocated element is still writable, and the |
385 // remainder element will be protected when the allocated one is). | 366 // remainder element will be protected when the allocated one is). |
386 if (is_protected && | 367 if (is_protected && |
387 !VirtualMemory::InSamePage(remainder_address - 1, remainder_address)) { | 368 !VirtualMemory::InSamePage(remainder_address - 1, remainder_address)) { |
388 bool status = | 369 bool status = |
389 VirtualMemory::Protect(reinterpret_cast<void*>(remainder_address), | 370 VirtualMemory::Protect(reinterpret_cast<void*>(remainder_address), |
390 remainder_size, VirtualMemory::kReadExecute); | 371 remainder_size, VirtualMemory::kReadExecute); |
391 ASSERT(status); | 372 ASSERT(status); |
392 } | 373 } |
393 } | 374 } |
394 | 375 |
395 | |
396 FreeListElement* FreeList::TryAllocateLarge(intptr_t minimum_size) { | 376 FreeListElement* FreeList::TryAllocateLarge(intptr_t minimum_size) { |
397 MutexLocker ml(mutex_); | 377 MutexLocker ml(mutex_); |
398 return TryAllocateLargeLocked(minimum_size); | 378 return TryAllocateLargeLocked(minimum_size); |
399 } | 379 } |
400 | 380 |
401 | |
402 FreeListElement* FreeList::TryAllocateLargeLocked(intptr_t minimum_size) { | 381 FreeListElement* FreeList::TryAllocateLargeLocked(intptr_t minimum_size) { |
403 DEBUG_ASSERT(mutex_->IsOwnedByCurrentThread()); | 382 DEBUG_ASSERT(mutex_->IsOwnedByCurrentThread()); |
404 FreeListElement* previous = NULL; | 383 FreeListElement* previous = NULL; |
405 FreeListElement* current = free_lists_[kNumLists]; | 384 FreeListElement* current = free_lists_[kNumLists]; |
406 // TODO(koda): Find largest. | 385 // TODO(koda): Find largest. |
407 // We are willing to search the freelist further for a big block. | 386 // We are willing to search the freelist further for a big block. |
408 intptr_t tries_left = | 387 intptr_t tries_left = |
409 freelist_search_budget_ + (minimum_size >> kWordSizeLog2); | 388 freelist_search_budget_ + (minimum_size >> kWordSizeLog2); |
410 while (current != NULL) { | 389 while (current != NULL) { |
411 FreeListElement* next = current->next(); | 390 FreeListElement* next = current->next(); |
412 if (current->Size() >= minimum_size) { | 391 if (current->Size() >= minimum_size) { |
413 if (previous == NULL) { | 392 if (previous == NULL) { |
414 free_lists_[kNumLists] = next; | 393 free_lists_[kNumLists] = next; |
415 } else { | 394 } else { |
416 previous->set_next(next); | 395 previous->set_next(next); |
417 } | 396 } |
418 freelist_search_budget_ = | 397 freelist_search_budget_ = |
419 Utils::Minimum(tries_left, kInitialFreeListSearchBudget); | 398 Utils::Minimum(tries_left, kInitialFreeListSearchBudget); |
420 return current; | 399 return current; |
421 } else if (tries_left-- < 0) { | 400 } else if (tries_left-- < 0) { |
422 freelist_search_budget_ = kInitialFreeListSearchBudget; | 401 freelist_search_budget_ = kInitialFreeListSearchBudget; |
423 return 0; // Trigger allocation of new page. | 402 return 0; // Trigger allocation of new page. |
424 } | 403 } |
425 previous = current; | 404 previous = current; |
426 current = next; | 405 current = next; |
427 } | 406 } |
428 return NULL; | 407 return NULL; |
429 } | 408 } |
430 | 409 |
431 | |
432 uword FreeList::TryAllocateSmallLocked(intptr_t size) { | 410 uword FreeList::TryAllocateSmallLocked(intptr_t size) { |
433 DEBUG_ASSERT(mutex_->IsOwnedByCurrentThread()); | 411 DEBUG_ASSERT(mutex_->IsOwnedByCurrentThread()); |
434 if (size > last_free_small_size_) { | 412 if (size > last_free_small_size_) { |
435 return 0; | 413 return 0; |
436 } | 414 } |
437 int index = IndexForSize(size); | 415 int index = IndexForSize(size); |
438 if (index != kNumLists && free_map_.Test(index)) { | 416 if (index != kNumLists && free_map_.Test(index)) { |
439 return reinterpret_cast<uword>(DequeueElement(index)); | 417 return reinterpret_cast<uword>(DequeueElement(index)); |
440 } | 418 } |
441 if ((index + 1) < kNumLists) { | 419 if ((index + 1) < kNumLists) { |
442 intptr_t next_index = free_map_.Next(index + 1); | 420 intptr_t next_index = free_map_.Next(index + 1); |
443 if (next_index != -1) { | 421 if (next_index != -1) { |
444 FreeListElement* element = DequeueElement(next_index); | 422 FreeListElement* element = DequeueElement(next_index); |
445 SplitElementAfterAndEnqueue(element, size, false); | 423 SplitElementAfterAndEnqueue(element, size, false); |
446 return reinterpret_cast<uword>(element); | 424 return reinterpret_cast<uword>(element); |
447 } | 425 } |
448 } | 426 } |
449 return 0; | 427 return 0; |
450 } | 428 } |
451 | 429 |
452 } // namespace dart | 430 } // namespace dart |
OLD | NEW |