OLD | NEW |
1 // Copyright 2006-2010 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2010 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 24 matching lines...) Expand all Loading... |
35 namespace v8 { | 35 namespace v8 { |
36 namespace internal { | 36 namespace internal { |
37 | 37 |
38 // For contiguous spaces, top should be in the space (or at the end) and limit | 38 // For contiguous spaces, top should be in the space (or at the end) and limit |
39 // should be the end of the space. | 39 // should be the end of the space. |
40 #define ASSERT_SEMISPACE_ALLOCATION_INFO(info, space) \ | 40 #define ASSERT_SEMISPACE_ALLOCATION_INFO(info, space) \ |
41 ASSERT((space).low() <= (info).top \ | 41 ASSERT((space).low() <= (info).top \ |
42 && (info).top <= (space).high() \ | 42 && (info).top <= (space).high() \ |
43 && (info).limit == (space).high()) | 43 && (info).limit == (space).high()) |
44 | 44 |
45 intptr_t Page::watermark_invalidated_mark_ = 1 << Page::WATERMARK_INVALIDATED; | |
46 | |
47 // ---------------------------------------------------------------------------- | 45 // ---------------------------------------------------------------------------- |
48 // HeapObjectIterator | 46 // HeapObjectIterator |
49 | 47 |
50 HeapObjectIterator::HeapObjectIterator(PagedSpace* space) { | 48 HeapObjectIterator::HeapObjectIterator(PagedSpace* space) { |
51 Initialize(space->bottom(), space->top(), NULL); | 49 Initialize(space->bottom(), space->top(), NULL); |
52 } | 50 } |
53 | 51 |
54 | 52 |
55 HeapObjectIterator::HeapObjectIterator(PagedSpace* space, | 53 HeapObjectIterator::HeapObjectIterator(PagedSpace* space, |
56 HeapObjectCallback size_func) { | 54 HeapObjectCallback size_func) { |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
142 #endif | 140 #endif |
143 stop_page_ = space->last_page_; | 141 stop_page_ = space->last_page_; |
144 break; | 142 break; |
145 } | 143 } |
146 } | 144 } |
147 | 145 |
148 | 146 |
149 // ----------------------------------------------------------------------------- | 147 // ----------------------------------------------------------------------------- |
150 // CodeRange | 148 // CodeRange |
151 | 149 |
152 List<CodeRange::FreeBlock> CodeRange::free_list_(0); | 150 |
153 List<CodeRange::FreeBlock> CodeRange::allocation_list_(0); | 151 CodeRange::CodeRange() |
154 int CodeRange::current_allocation_block_index_ = 0; | 152 : code_range_(NULL), |
155 VirtualMemory* CodeRange::code_range_ = NULL; | 153 free_list_(0), |
| 154 allocation_list_(0), |
| 155 current_allocation_block_index_(0), |
| 156 isolate_(NULL) { |
| 157 } |
156 | 158 |
157 | 159 |
158 bool CodeRange::Setup(const size_t requested) { | 160 bool CodeRange::Setup(const size_t requested) { |
159 ASSERT(code_range_ == NULL); | 161 ASSERT(code_range_ == NULL); |
160 | 162 |
161 code_range_ = new VirtualMemory(requested); | 163 code_range_ = new VirtualMemory(requested); |
162 CHECK(code_range_ != NULL); | 164 CHECK(code_range_ != NULL); |
163 if (!code_range_->IsReserved()) { | 165 if (!code_range_->IsReserved()) { |
164 delete code_range_; | 166 delete code_range_; |
165 code_range_ = NULL; | 167 code_range_ = NULL; |
166 return false; | 168 return false; |
167 } | 169 } |
168 | 170 |
169 // We are sure that we have mapped a block of requested addresses. | 171 // We are sure that we have mapped a block of requested addresses. |
170 ASSERT(code_range_->size() == requested); | 172 ASSERT(code_range_->size() == requested); |
171 LOG(NewEvent("CodeRange", code_range_->address(), requested)); | 173 LOG(isolate_, NewEvent("CodeRange", code_range_->address(), requested)); |
172 allocation_list_.Add(FreeBlock(code_range_->address(), code_range_->size())); | 174 allocation_list_.Add(FreeBlock(code_range_->address(), code_range_->size())); |
173 current_allocation_block_index_ = 0; | 175 current_allocation_block_index_ = 0; |
174 return true; | 176 return true; |
175 } | 177 } |
176 | 178 |
177 | 179 |
178 int CodeRange::CompareFreeBlockAddress(const FreeBlock* left, | 180 int CodeRange::CompareFreeBlockAddress(const FreeBlock* left, |
179 const FreeBlock* right) { | 181 const FreeBlock* right) { |
180 // The entire point of CodeRange is that the difference between two | 182 // The entire point of CodeRange is that the difference between two |
181 // addresses in the range can be represented as a signed 32-bit int, | 183 // addresses in the range can be represented as a signed 32-bit int, |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
264 delete code_range_; // Frees all memory in the virtual memory range. | 266 delete code_range_; // Frees all memory in the virtual memory range. |
265 code_range_ = NULL; | 267 code_range_ = NULL; |
266 free_list_.Free(); | 268 free_list_.Free(); |
267 allocation_list_.Free(); | 269 allocation_list_.Free(); |
268 } | 270 } |
269 | 271 |
270 | 272 |
271 // ----------------------------------------------------------------------------- | 273 // ----------------------------------------------------------------------------- |
272 // MemoryAllocator | 274 // MemoryAllocator |
273 // | 275 // |
274 intptr_t MemoryAllocator::capacity_ = 0; | |
275 intptr_t MemoryAllocator::capacity_executable_ = 0; | |
276 intptr_t MemoryAllocator::size_ = 0; | |
277 intptr_t MemoryAllocator::size_executable_ = 0; | |
278 | |
279 List<MemoryAllocator::MemoryAllocationCallbackRegistration> | |
280 MemoryAllocator::memory_allocation_callbacks_; | |
281 | |
282 VirtualMemory* MemoryAllocator::initial_chunk_ = NULL; | |
283 | 276 |
284 // 270 is an estimate based on the static default heap size of a pair of 256K | 277 // 270 is an estimate based on the static default heap size of a pair of 256K |
285 // semispaces and a 64M old generation. | 278 // semispaces and a 64M old generation. |
286 const int kEstimatedNumberOfChunks = 270; | 279 const int kEstimatedNumberOfChunks = 270; |
287 List<MemoryAllocator::ChunkInfo> MemoryAllocator::chunks_( | 280 |
288 kEstimatedNumberOfChunks); | 281 |
289 List<int> MemoryAllocator::free_chunk_ids_(kEstimatedNumberOfChunks); | 282 MemoryAllocator::MemoryAllocator() |
290 int MemoryAllocator::max_nof_chunks_ = 0; | 283 : capacity_(0), |
291 int MemoryAllocator::top_ = 0; | 284 capacity_executable_(0), |
| 285 size_(0), |
| 286 size_executable_(0), |
| 287 initial_chunk_(NULL), |
| 288 chunks_(kEstimatedNumberOfChunks), |
| 289 free_chunk_ids_(kEstimatedNumberOfChunks), |
| 290 max_nof_chunks_(0), |
| 291 top_(0), |
| 292 isolate_(NULL) { |
| 293 } |
292 | 294 |
293 | 295 |
294 void MemoryAllocator::Push(int free_chunk_id) { | 296 void MemoryAllocator::Push(int free_chunk_id) { |
295 ASSERT(max_nof_chunks_ > 0); | 297 ASSERT(max_nof_chunks_ > 0); |
296 ASSERT(top_ < max_nof_chunks_); | 298 ASSERT(top_ < max_nof_chunks_); |
297 free_chunk_ids_[top_++] = free_chunk_id; | 299 free_chunk_ids_[top_++] = free_chunk_id; |
298 } | 300 } |
299 | 301 |
300 | 302 |
301 int MemoryAllocator::Pop() { | 303 int MemoryAllocator::Pop() { |
(...skipping 25 matching lines...) Expand all Loading... |
327 ChunkInfo info; // uninitialized element. | 329 ChunkInfo info; // uninitialized element. |
328 for (int i = max_nof_chunks_ - 1; i >= 0; i--) { | 330 for (int i = max_nof_chunks_ - 1; i >= 0; i--) { |
329 chunks_.Add(info); | 331 chunks_.Add(info); |
330 free_chunk_ids_.Add(i); | 332 free_chunk_ids_.Add(i); |
331 } | 333 } |
332 top_ = max_nof_chunks_; | 334 top_ = max_nof_chunks_; |
333 return true; | 335 return true; |
334 } | 336 } |
335 | 337 |
336 | 338 |
337 bool MemoryAllocator::SafeIsInAPageChunk(Address addr) { | |
338 return InInitialChunk(addr) || InAllocatedChunks(addr); | |
339 } | |
340 | |
341 | |
342 void MemoryAllocator::TearDown() { | 339 void MemoryAllocator::TearDown() { |
343 for (int i = 0; i < max_nof_chunks_; i++) { | 340 for (int i = 0; i < max_nof_chunks_; i++) { |
344 if (chunks_[i].address() != NULL) DeleteChunk(i); | 341 if (chunks_[i].address() != NULL) DeleteChunk(i); |
345 } | 342 } |
346 chunks_.Clear(); | 343 chunks_.Clear(); |
347 free_chunk_ids_.Clear(); | 344 free_chunk_ids_.Clear(); |
348 | 345 |
349 if (initial_chunk_ != NULL) { | 346 if (initial_chunk_ != NULL) { |
350 LOG(DeleteEvent("InitialChunk", initial_chunk_->address())); | 347 LOG(isolate_, DeleteEvent("InitialChunk", initial_chunk_->address())); |
351 delete initial_chunk_; | 348 delete initial_chunk_; |
352 initial_chunk_ = NULL; | 349 initial_chunk_ = NULL; |
353 } | 350 } |
354 | 351 |
355 FreeChunkTables(&chunk_table_[0], | |
356 kChunkTableTopLevelEntries, | |
357 kChunkTableLevels); | |
358 | |
359 ASSERT(top_ == max_nof_chunks_); // all chunks are free | 352 ASSERT(top_ == max_nof_chunks_); // all chunks are free |
360 top_ = 0; | 353 top_ = 0; |
361 capacity_ = 0; | 354 capacity_ = 0; |
362 capacity_executable_ = 0; | 355 capacity_executable_ = 0; |
363 size_ = 0; | 356 size_ = 0; |
364 max_nof_chunks_ = 0; | 357 max_nof_chunks_ = 0; |
365 } | 358 } |
366 | 359 |
367 | 360 |
368 void MemoryAllocator::FreeChunkTables(uintptr_t* array, int len, int level) { | |
369 for (int i = 0; i < len; i++) { | |
370 if (array[i] != kUnusedChunkTableEntry) { | |
371 uintptr_t* subarray = reinterpret_cast<uintptr_t*>(array[i]); | |
372 if (level > 1) { | |
373 array[i] = kUnusedChunkTableEntry; | |
374 FreeChunkTables(subarray, 1 << kChunkTableBitsPerLevel, level - 1); | |
375 } else { | |
376 array[i] = kUnusedChunkTableEntry; | |
377 } | |
378 delete[] subarray; | |
379 } | |
380 } | |
381 } | |
382 | |
383 | |
384 void* MemoryAllocator::AllocateRawMemory(const size_t requested, | 361 void* MemoryAllocator::AllocateRawMemory(const size_t requested, |
385 size_t* allocated, | 362 size_t* allocated, |
386 Executability executable) { | 363 Executability executable) { |
387 if (size_ + static_cast<size_t>(requested) > static_cast<size_t>(capacity_)) { | 364 if (size_ + static_cast<size_t>(requested) > static_cast<size_t>(capacity_)) { |
388 return NULL; | 365 return NULL; |
389 } | 366 } |
390 | 367 |
391 void* mem; | 368 void* mem; |
392 if (executable == EXECUTABLE) { | 369 if (executable == EXECUTABLE) { |
393 // Check executable memory limit. | 370 // Check executable memory limit. |
394 if (size_executable_ + requested > | 371 if (size_executable_ + requested > |
395 static_cast<size_t>(capacity_executable_)) { | 372 static_cast<size_t>(capacity_executable_)) { |
396 LOG(StringEvent("MemoryAllocator::AllocateRawMemory", | 373 LOG(isolate_, |
| 374 StringEvent("MemoryAllocator::AllocateRawMemory", |
397 "V8 Executable Allocation capacity exceeded")); | 375 "V8 Executable Allocation capacity exceeded")); |
398 return NULL; | 376 return NULL; |
399 } | 377 } |
400 // Allocate executable memory either from code range or from the | 378 // Allocate executable memory either from code range or from the |
401 // OS. | 379 // OS. |
402 if (CodeRange::exists()) { | 380 if (isolate_->code_range()->exists()) { |
403 mem = CodeRange::AllocateRawMemory(requested, allocated); | 381 mem = isolate_->code_range()->AllocateRawMemory(requested, allocated); |
404 } else { | 382 } else { |
405 mem = OS::Allocate(requested, allocated, true); | 383 mem = OS::Allocate(requested, allocated, true); |
406 } | 384 } |
407 // Update executable memory size. | 385 // Update executable memory size. |
408 size_executable_ += static_cast<int>(*allocated); | 386 size_executable_ += static_cast<int>(*allocated); |
409 } else { | 387 } else { |
410 mem = OS::Allocate(requested, allocated, false); | 388 mem = OS::Allocate(requested, allocated, false); |
411 } | 389 } |
412 int alloced = static_cast<int>(*allocated); | 390 int alloced = static_cast<int>(*allocated); |
413 size_ += alloced; | 391 size_ += alloced; |
414 | 392 |
415 #ifdef DEBUG | 393 #ifdef DEBUG |
416 ZapBlock(reinterpret_cast<Address>(mem), alloced); | 394 ZapBlock(reinterpret_cast<Address>(mem), alloced); |
417 #endif | 395 #endif |
418 Counters::memory_allocated.Increment(alloced); | 396 COUNTERS->memory_allocated()->Increment(alloced); |
419 return mem; | 397 return mem; |
420 } | 398 } |
421 | 399 |
422 | 400 |
423 void MemoryAllocator::FreeRawMemory(void* mem, | 401 void MemoryAllocator::FreeRawMemory(void* mem, |
424 size_t length, | 402 size_t length, |
425 Executability executable) { | 403 Executability executable) { |
426 #ifdef DEBUG | 404 #ifdef DEBUG |
427 ZapBlock(reinterpret_cast<Address>(mem), length); | 405 ZapBlock(reinterpret_cast<Address>(mem), length); |
428 #endif | 406 #endif |
429 if (CodeRange::contains(static_cast<Address>(mem))) { | 407 if (isolate_->code_range()->contains(static_cast<Address>(mem))) { |
430 CodeRange::FreeRawMemory(mem, length); | 408 isolate_->code_range()->FreeRawMemory(mem, length); |
431 } else { | 409 } else { |
432 OS::Free(mem, length); | 410 OS::Free(mem, length); |
433 } | 411 } |
434 Counters::memory_allocated.Decrement(static_cast<int>(length)); | 412 COUNTERS->memory_allocated()->Decrement(static_cast<int>(length)); |
435 size_ -= static_cast<int>(length); | 413 size_ -= static_cast<int>(length); |
436 if (executable == EXECUTABLE) size_executable_ -= static_cast<int>(length); | 414 if (executable == EXECUTABLE) size_executable_ -= static_cast<int>(length); |
437 | 415 |
438 ASSERT(size_ >= 0); | 416 ASSERT(size_ >= 0); |
439 ASSERT(size_executable_ >= 0); | 417 ASSERT(size_executable_ >= 0); |
440 } | 418 } |
441 | 419 |
442 | 420 |
443 void MemoryAllocator::PerformAllocationCallback(ObjectSpace space, | 421 void MemoryAllocator::PerformAllocationCallback(ObjectSpace space, |
444 AllocationAction action, | 422 AllocationAction action, |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
491 initial_chunk_ = new VirtualMemory(requested); | 469 initial_chunk_ = new VirtualMemory(requested); |
492 CHECK(initial_chunk_ != NULL); | 470 CHECK(initial_chunk_ != NULL); |
493 if (!initial_chunk_->IsReserved()) { | 471 if (!initial_chunk_->IsReserved()) { |
494 delete initial_chunk_; | 472 delete initial_chunk_; |
495 initial_chunk_ = NULL; | 473 initial_chunk_ = NULL; |
496 return NULL; | 474 return NULL; |
497 } | 475 } |
498 | 476 |
499 // We are sure that we have mapped a block of requested addresses. | 477 // We are sure that we have mapped a block of requested addresses. |
500 ASSERT(initial_chunk_->size() == requested); | 478 ASSERT(initial_chunk_->size() == requested); |
501 LOG(NewEvent("InitialChunk", initial_chunk_->address(), requested)); | 479 LOG(isolate_, |
| 480 NewEvent("InitialChunk", initial_chunk_->address(), requested)); |
502 size_ += static_cast<int>(requested); | 481 size_ += static_cast<int>(requested); |
503 return initial_chunk_->address(); | 482 return initial_chunk_->address(); |
504 } | 483 } |
505 | 484 |
506 | 485 |
507 static int PagesInChunk(Address start, size_t size) { | 486 static int PagesInChunk(Address start, size_t size) { |
508 // The first page starts on the first page-aligned address from start onward | 487 // The first page starts on the first page-aligned address from start onward |
509 // and the last page ends on the last page-aligned address before | 488 // and the last page ends on the last page-aligned address before |
510 // start+size. Page::kPageSize is a power of two so we can divide by | 489 // start+size. Page::kPageSize is a power of two so we can divide by |
511 // shifting. | 490 // shifting. |
512 return static_cast<int>((RoundDown(start + size, Page::kPageSize) | 491 return static_cast<int>((RoundDown(start + size, Page::kPageSize) |
513 - RoundUp(start, Page::kPageSize)) >> kPageSizeBits); | 492 - RoundUp(start, Page::kPageSize)) >> kPageSizeBits); |
514 } | 493 } |
515 | 494 |
516 | 495 |
517 Page* MemoryAllocator::AllocatePages(int requested_pages, | 496 Page* MemoryAllocator::AllocatePages(int requested_pages, |
518 int* allocated_pages, | 497 int* allocated_pages, |
519 PagedSpace* owner) { | 498 PagedSpace* owner) { |
520 if (requested_pages <= 0) return Page::FromAddress(NULL); | 499 if (requested_pages <= 0) return Page::FromAddress(NULL); |
521 size_t chunk_size = requested_pages * Page::kPageSize; | 500 size_t chunk_size = requested_pages * Page::kPageSize; |
522 | 501 |
523 void* chunk = AllocateRawMemory(chunk_size, &chunk_size, owner->executable()); | 502 void* chunk = AllocateRawMemory(chunk_size, &chunk_size, owner->executable()); |
524 if (chunk == NULL) return Page::FromAddress(NULL); | 503 if (chunk == NULL) return Page::FromAddress(NULL); |
525 LOG(NewEvent("PagedChunk", chunk, chunk_size)); | 504 LOG(isolate_, NewEvent("PagedChunk", chunk, chunk_size)); |
526 | 505 |
527 *allocated_pages = PagesInChunk(static_cast<Address>(chunk), chunk_size); | 506 *allocated_pages = PagesInChunk(static_cast<Address>(chunk), chunk_size); |
528 // We may 'lose' a page due to alignment. | 507 // We may 'lose' a page due to alignment. |
529 ASSERT(*allocated_pages >= kPagesPerChunk - 1); | 508 ASSERT(*allocated_pages >= kPagesPerChunk - 1); |
530 if (*allocated_pages == 0) { | 509 if (*allocated_pages == 0) { |
531 FreeRawMemory(chunk, chunk_size, owner->executable()); | 510 FreeRawMemory(chunk, chunk_size, owner->executable()); |
532 LOG(DeleteEvent("PagedChunk", chunk)); | 511 LOG(isolate_, DeleteEvent("PagedChunk", chunk)); |
533 return Page::FromAddress(NULL); | 512 return Page::FromAddress(NULL); |
534 } | 513 } |
535 | 514 |
536 int chunk_id = Pop(); | 515 int chunk_id = Pop(); |
537 chunks_[chunk_id].init(static_cast<Address>(chunk), chunk_size, owner); | 516 chunks_[chunk_id].init(static_cast<Address>(chunk), chunk_size, owner); |
538 | 517 |
539 ObjectSpace space = static_cast<ObjectSpace>(1 << owner->identity()); | 518 ObjectSpace space = static_cast<ObjectSpace>(1 << owner->identity()); |
540 PerformAllocationCallback(space, kAllocationActionAllocate, chunk_size); | 519 PerformAllocationCallback(space, kAllocationActionAllocate, chunk_size); |
541 Page* new_pages = InitializePagesInChunk(chunk_id, *allocated_pages, owner); | 520 Page* new_pages = InitializePagesInChunk(chunk_id, *allocated_pages, owner); |
542 | 521 |
543 AddToAllocatedChunks(static_cast<Address>(chunk), chunk_size); | |
544 | |
545 return new_pages; | 522 return new_pages; |
546 } | 523 } |
547 | 524 |
548 | 525 |
549 Page* MemoryAllocator::CommitPages(Address start, size_t size, | 526 Page* MemoryAllocator::CommitPages(Address start, size_t size, |
550 PagedSpace* owner, int* num_pages) { | 527 PagedSpace* owner, int* num_pages) { |
551 ASSERT(start != NULL); | 528 ASSERT(start != NULL); |
552 *num_pages = PagesInChunk(start, size); | 529 *num_pages = PagesInChunk(start, size); |
553 ASSERT(*num_pages > 0); | 530 ASSERT(*num_pages > 0); |
554 ASSERT(initial_chunk_ != NULL); | 531 ASSERT(initial_chunk_ != NULL); |
555 ASSERT(InInitialChunk(start)); | 532 ASSERT(InInitialChunk(start)); |
556 ASSERT(InInitialChunk(start + size - 1)); | 533 ASSERT(InInitialChunk(start + size - 1)); |
557 if (!initial_chunk_->Commit(start, size, owner->executable() == EXECUTABLE)) { | 534 if (!initial_chunk_->Commit(start, size, owner->executable() == EXECUTABLE)) { |
558 return Page::FromAddress(NULL); | 535 return Page::FromAddress(NULL); |
559 } | 536 } |
560 #ifdef DEBUG | 537 #ifdef DEBUG |
561 ZapBlock(start, size); | 538 ZapBlock(start, size); |
562 #endif | 539 #endif |
563 Counters::memory_allocated.Increment(static_cast<int>(size)); | 540 COUNTERS->memory_allocated()->Increment(static_cast<int>(size)); |
564 | 541 |
565 // So long as we correctly overestimated the number of chunks we should not | 542 // So long as we correctly overestimated the number of chunks we should not |
566 // run out of chunk ids. | 543 // run out of chunk ids. |
567 CHECK(!OutOfChunkIds()); | 544 CHECK(!OutOfChunkIds()); |
568 int chunk_id = Pop(); | 545 int chunk_id = Pop(); |
569 chunks_[chunk_id].init(start, size, owner); | 546 chunks_[chunk_id].init(start, size, owner); |
570 return InitializePagesInChunk(chunk_id, *num_pages, owner); | 547 return InitializePagesInChunk(chunk_id, *num_pages, owner); |
571 } | 548 } |
572 | 549 |
573 | 550 |
574 bool MemoryAllocator::CommitBlock(Address start, | 551 bool MemoryAllocator::CommitBlock(Address start, |
575 size_t size, | 552 size_t size, |
576 Executability executable) { | 553 Executability executable) { |
577 ASSERT(start != NULL); | 554 ASSERT(start != NULL); |
578 ASSERT(size > 0); | 555 ASSERT(size > 0); |
579 ASSERT(initial_chunk_ != NULL); | 556 ASSERT(initial_chunk_ != NULL); |
580 ASSERT(InInitialChunk(start)); | 557 ASSERT(InInitialChunk(start)); |
581 ASSERT(InInitialChunk(start + size - 1)); | 558 ASSERT(InInitialChunk(start + size - 1)); |
582 | 559 |
583 if (!initial_chunk_->Commit(start, size, executable)) return false; | 560 if (!initial_chunk_->Commit(start, size, executable)) return false; |
584 #ifdef DEBUG | 561 #ifdef DEBUG |
585 ZapBlock(start, size); | 562 ZapBlock(start, size); |
586 #endif | 563 #endif |
587 Counters::memory_allocated.Increment(static_cast<int>(size)); | 564 COUNTERS->memory_allocated()->Increment(static_cast<int>(size)); |
588 return true; | 565 return true; |
589 } | 566 } |
590 | 567 |
591 | 568 |
592 bool MemoryAllocator::UncommitBlock(Address start, size_t size) { | 569 bool MemoryAllocator::UncommitBlock(Address start, size_t size) { |
593 ASSERT(start != NULL); | 570 ASSERT(start != NULL); |
594 ASSERT(size > 0); | 571 ASSERT(size > 0); |
595 ASSERT(initial_chunk_ != NULL); | 572 ASSERT(initial_chunk_ != NULL); |
596 ASSERT(InInitialChunk(start)); | 573 ASSERT(InInitialChunk(start)); |
597 ASSERT(InInitialChunk(start + size - 1)); | 574 ASSERT(InInitialChunk(start + size - 1)); |
598 | 575 |
599 if (!initial_chunk_->Uncommit(start, size)) return false; | 576 if (!initial_chunk_->Uncommit(start, size)) return false; |
600 Counters::memory_allocated.Decrement(static_cast<int>(size)); | 577 COUNTERS->memory_allocated()->Decrement(static_cast<int>(size)); |
601 return true; | 578 return true; |
602 } | 579 } |
603 | 580 |
604 | 581 |
605 void MemoryAllocator::ZapBlock(Address start, size_t size) { | 582 void MemoryAllocator::ZapBlock(Address start, size_t size) { |
606 for (size_t s = 0; s + kPointerSize <= size; s += kPointerSize) { | 583 for (size_t s = 0; s + kPointerSize <= size; s += kPointerSize) { |
607 Memory::Address_at(start + s) = kZapValue; | 584 Memory::Address_at(start + s) = kZapValue; |
608 } | 585 } |
609 } | 586 } |
610 | 587 |
(...skipping 10 matching lines...) Expand all Loading... |
621 #ifdef DEBUG | 598 #ifdef DEBUG |
622 size_t chunk_size = chunks_[chunk_id].size(); | 599 size_t chunk_size = chunks_[chunk_id].size(); |
623 Address high = RoundDown(chunk_start + chunk_size, Page::kPageSize); | 600 Address high = RoundDown(chunk_start + chunk_size, Page::kPageSize); |
624 ASSERT(pages_in_chunk <= | 601 ASSERT(pages_in_chunk <= |
625 ((OffsetFrom(high) - OffsetFrom(low)) / Page::kPageSize)); | 602 ((OffsetFrom(high) - OffsetFrom(low)) / Page::kPageSize)); |
626 #endif | 603 #endif |
627 | 604 |
628 Address page_addr = low; | 605 Address page_addr = low; |
629 for (int i = 0; i < pages_in_chunk; i++) { | 606 for (int i = 0; i < pages_in_chunk; i++) { |
630 Page* p = Page::FromAddress(page_addr); | 607 Page* p = Page::FromAddress(page_addr); |
| 608 p->heap_ = owner->heap(); |
631 p->opaque_header = OffsetFrom(page_addr + Page::kPageSize) | chunk_id; | 609 p->opaque_header = OffsetFrom(page_addr + Page::kPageSize) | chunk_id; |
632 p->InvalidateWatermark(true); | 610 p->InvalidateWatermark(true); |
633 p->SetIsLargeObjectPage(false); | 611 p->SetIsLargeObjectPage(false); |
634 p->SetAllocationWatermark(p->ObjectAreaStart()); | 612 p->SetAllocationWatermark(p->ObjectAreaStart()); |
635 p->SetCachedAllocationWatermark(p->ObjectAreaStart()); | 613 p->SetCachedAllocationWatermark(p->ObjectAreaStart()); |
636 page_addr += Page::kPageSize; | 614 page_addr += Page::kPageSize; |
637 } | 615 } |
638 | 616 |
639 // Set the next page of the last page to 0. | 617 // Set the next page of the last page to 0. |
640 Page* last_page = Page::FromAddress(page_addr - Page::kPageSize); | 618 Page* last_page = Page::FromAddress(page_addr - Page::kPageSize); |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
690 | 668 |
691 ChunkInfo& c = chunks_[chunk_id]; | 669 ChunkInfo& c = chunks_[chunk_id]; |
692 | 670 |
693 // We cannot free a chunk contained in the initial chunk because it was not | 671 // We cannot free a chunk contained in the initial chunk because it was not |
694 // allocated with AllocateRawMemory. Instead we uncommit the virtual | 672 // allocated with AllocateRawMemory. Instead we uncommit the virtual |
695 // memory. | 673 // memory. |
696 if (InInitialChunk(c.address())) { | 674 if (InInitialChunk(c.address())) { |
697 // TODO(1240712): VirtualMemory::Uncommit has a return value which | 675 // TODO(1240712): VirtualMemory::Uncommit has a return value which |
698 // is ignored here. | 676 // is ignored here. |
699 initial_chunk_->Uncommit(c.address(), c.size()); | 677 initial_chunk_->Uncommit(c.address(), c.size()); |
700 Counters::memory_allocated.Decrement(static_cast<int>(c.size())); | 678 COUNTERS->memory_allocated()->Decrement(static_cast<int>(c.size())); |
701 } else { | 679 } else { |
702 RemoveFromAllocatedChunks(c.address(), c.size()); | 680 LOG(isolate_, DeleteEvent("PagedChunk", c.address())); |
703 LOG(DeleteEvent("PagedChunk", c.address())); | 681 ObjectSpace space = static_cast<ObjectSpace>(1 << c.owner_identity()); |
704 ObjectSpace space = static_cast<ObjectSpace>(1 << c.owner()->identity()); | |
705 size_t size = c.size(); | 682 size_t size = c.size(); |
706 FreeRawMemory(c.address(), size, c.executable()); | 683 FreeRawMemory(c.address(), size, c.executable()); |
707 PerformAllocationCallback(space, kAllocationActionFree, size); | 684 PerformAllocationCallback(space, kAllocationActionFree, size); |
708 } | 685 } |
709 c.init(NULL, 0, NULL); | 686 c.init(NULL, 0, NULL); |
710 Push(chunk_id); | 687 Push(chunk_id); |
711 } | 688 } |
712 | 689 |
713 | 690 |
714 Page* MemoryAllocator::FindFirstPageInSameChunk(Page* p) { | 691 Page* MemoryAllocator::FindFirstPageInSameChunk(Page* p) { |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
806 last_page->opaque_header = OffsetFrom(0) | chunk_id; | 783 last_page->opaque_header = OffsetFrom(0) | chunk_id; |
807 | 784 |
808 if (last_page->WasInUseBeforeMC()) { | 785 if (last_page->WasInUseBeforeMC()) { |
809 *last_page_in_use = last_page; | 786 *last_page_in_use = last_page; |
810 } | 787 } |
811 | 788 |
812 return last_page; | 789 return last_page; |
813 } | 790 } |
814 | 791 |
815 | 792 |
816 void MemoryAllocator::AddToAllocatedChunks(Address addr, intptr_t size) { | |
817 ASSERT(size == kChunkSize); | |
818 uintptr_t int_address = reinterpret_cast<uintptr_t>(addr); | |
819 AddChunkUsingAddress(int_address, int_address); | |
820 AddChunkUsingAddress(int_address, int_address + size - 1); | |
821 } | |
822 | |
823 | |
824 void MemoryAllocator::AddChunkUsingAddress(uintptr_t chunk_start, | |
825 uintptr_t chunk_index_base) { | |
826 uintptr_t* fine_grained = AllocatedChunksFinder( | |
827 chunk_table_, | |
828 chunk_index_base, | |
829 kChunkSizeLog2 + (kChunkTableLevels - 1) * kChunkTableBitsPerLevel, | |
830 kCreateTablesAsNeeded); | |
831 int index = FineGrainedIndexForAddress(chunk_index_base); | |
832 if (fine_grained[index] != kUnusedChunkTableEntry) index++; | |
833 ASSERT(fine_grained[index] == kUnusedChunkTableEntry); | |
834 fine_grained[index] = chunk_start; | |
835 } | |
836 | |
837 | |
838 void MemoryAllocator::RemoveFromAllocatedChunks(Address addr, intptr_t size) { | |
839 ASSERT(size == kChunkSize); | |
840 uintptr_t int_address = reinterpret_cast<uintptr_t>(addr); | |
841 RemoveChunkFoundUsingAddress(int_address, int_address); | |
842 RemoveChunkFoundUsingAddress(int_address, int_address + size - 1); | |
843 } | |
844 | |
845 | |
846 void MemoryAllocator::RemoveChunkFoundUsingAddress( | |
847 uintptr_t chunk_start, | |
848 uintptr_t chunk_index_base) { | |
849 uintptr_t* fine_grained = AllocatedChunksFinder( | |
850 chunk_table_, | |
851 chunk_index_base, | |
852 kChunkSizeLog2 + (kChunkTableLevels - 1) * kChunkTableBitsPerLevel, | |
853 kDontCreateTables); | |
854 // Can't remove an entry that's not there. | |
855 ASSERT(fine_grained != kUnusedChunkTableEntry); | |
856 int index = FineGrainedIndexForAddress(chunk_index_base); | |
857 ASSERT(fine_grained[index] != kUnusedChunkTableEntry); | |
858 if (fine_grained[index] != chunk_start) { | |
859 index++; | |
860 ASSERT(fine_grained[index] == chunk_start); | |
861 fine_grained[index] = kUnusedChunkTableEntry; | |
862 } else { | |
863 // If only one of the entries is used it must be the first, since | |
864 // InAllocatedChunks relies on that. Move things around so that this is | |
865 // the case. | |
866 fine_grained[index] = fine_grained[index + 1]; | |
867 fine_grained[index + 1] = kUnusedChunkTableEntry; | |
868 } | |
869 } | |
870 | |
871 | |
872 bool MemoryAllocator::InAllocatedChunks(Address addr) { | |
873 uintptr_t int_address = reinterpret_cast<uintptr_t>(addr); | |
874 uintptr_t* fine_grained = AllocatedChunksFinder( | |
875 chunk_table_, | |
876 int_address, | |
877 kChunkSizeLog2 + (kChunkTableLevels - 1) * kChunkTableBitsPerLevel, | |
878 kDontCreateTables); | |
879 if (fine_grained == NULL) return false; | |
880 int index = FineGrainedIndexForAddress(int_address); | |
881 if (fine_grained[index] == kUnusedChunkTableEntry) return false; | |
882 uintptr_t entry = fine_grained[index]; | |
883 if (entry <= int_address && entry + kChunkSize > int_address) return true; | |
884 index++; | |
885 if (fine_grained[index] == kUnusedChunkTableEntry) return false; | |
886 entry = fine_grained[index]; | |
887 if (entry <= int_address && entry + kChunkSize > int_address) return true; | |
888 return false; | |
889 } | |
890 | |
891 | |
892 uintptr_t* MemoryAllocator::AllocatedChunksFinder( | |
893 uintptr_t* table, | |
894 uintptr_t address, | |
895 int bit_position, | |
896 CreateTables create_as_needed) { | |
897 if (bit_position == kChunkSizeLog2) { | |
898 return table; | |
899 } | |
900 ASSERT(bit_position >= kChunkSizeLog2 + kChunkTableBitsPerLevel); | |
901 int index = | |
902 ((address >> bit_position) & | |
903 ((V8_INTPTR_C(1) << kChunkTableBitsPerLevel) - 1)); | |
904 uintptr_t more_fine_grained_address = | |
905 address & ((V8_INTPTR_C(1) << bit_position) - 1); | |
906 ASSERT((table == chunk_table_ && index < kChunkTableTopLevelEntries) || | |
907 (table != chunk_table_ && index < 1 << kChunkTableBitsPerLevel)); | |
908 uintptr_t* more_fine_grained_table = | |
909 reinterpret_cast<uintptr_t*>(table[index]); | |
910 if (more_fine_grained_table == kUnusedChunkTableEntry) { | |
911 if (create_as_needed == kDontCreateTables) return NULL; | |
912 int words_needed = 1 << kChunkTableBitsPerLevel; | |
913 if (bit_position == kChunkTableBitsPerLevel + kChunkSizeLog2) { | |
914 words_needed = | |
915 (1 << kChunkTableBitsPerLevel) * kChunkTableFineGrainedWordsPerEntry; | |
916 } | |
917 more_fine_grained_table = new uintptr_t[words_needed]; | |
918 for (int i = 0; i < words_needed; i++) { | |
919 more_fine_grained_table[i] = kUnusedChunkTableEntry; | |
920 } | |
921 table[index] = reinterpret_cast<uintptr_t>(more_fine_grained_table); | |
922 } | |
923 return AllocatedChunksFinder( | |
924 more_fine_grained_table, | |
925 more_fine_grained_address, | |
926 bit_position - kChunkTableBitsPerLevel, | |
927 create_as_needed); | |
928 } | |
929 | |
930 | |
931 uintptr_t MemoryAllocator::chunk_table_[kChunkTableTopLevelEntries]; | |
932 | |
933 | |
934 // ----------------------------------------------------------------------------- | 793 // ----------------------------------------------------------------------------- |
935 // PagedSpace implementation | 794 // PagedSpace implementation |
936 | 795 |
937 PagedSpace::PagedSpace(intptr_t max_capacity, | 796 PagedSpace::PagedSpace(Heap* heap, |
| 797 intptr_t max_capacity, |
938 AllocationSpace id, | 798 AllocationSpace id, |
939 Executability executable) | 799 Executability executable) |
940 : Space(id, executable) { | 800 : Space(heap, id, executable) { |
941 max_capacity_ = (RoundDown(max_capacity, Page::kPageSize) / Page::kPageSize) | 801 max_capacity_ = (RoundDown(max_capacity, Page::kPageSize) / Page::kPageSize) |
942 * Page::kObjectAreaSize; | 802 * Page::kObjectAreaSize; |
943 accounting_stats_.Clear(); | 803 accounting_stats_.Clear(); |
944 | 804 |
945 allocation_info_.top = NULL; | 805 allocation_info_.top = NULL; |
946 allocation_info_.limit = NULL; | 806 allocation_info_.limit = NULL; |
947 | 807 |
948 mc_forwarding_info_.top = NULL; | 808 mc_forwarding_info_.top = NULL; |
949 mc_forwarding_info_.limit = NULL; | 809 mc_forwarding_info_.limit = NULL; |
950 } | 810 } |
951 | 811 |
952 | 812 |
953 bool PagedSpace::Setup(Address start, size_t size) { | 813 bool PagedSpace::Setup(Address start, size_t size) { |
954 if (HasBeenSetup()) return false; | 814 if (HasBeenSetup()) return false; |
955 | 815 |
956 int num_pages = 0; | 816 int num_pages = 0; |
957 // Try to use the virtual memory range passed to us. If it is too small to | 817 // Try to use the virtual memory range passed to us. If it is too small to |
958 // contain at least one page, ignore it and allocate instead. | 818 // contain at least one page, ignore it and allocate instead. |
959 int pages_in_chunk = PagesInChunk(start, size); | 819 int pages_in_chunk = PagesInChunk(start, size); |
960 if (pages_in_chunk > 0) { | 820 if (pages_in_chunk > 0) { |
961 first_page_ = MemoryAllocator::CommitPages(RoundUp(start, Page::kPageSize), | 821 first_page_ = Isolate::Current()->memory_allocator()->CommitPages( |
962 Page::kPageSize * pages_in_chunk, | 822 RoundUp(start, Page::kPageSize), |
963 this, &num_pages); | 823 Page::kPageSize * pages_in_chunk, |
| 824 this, &num_pages); |
964 } else { | 825 } else { |
965 int requested_pages = | 826 int requested_pages = |
966 Min(MemoryAllocator::kPagesPerChunk, | 827 Min(MemoryAllocator::kPagesPerChunk, |
967 static_cast<int>(max_capacity_ / Page::kObjectAreaSize)); | 828 static_cast<int>(max_capacity_ / Page::kObjectAreaSize)); |
968 first_page_ = | 829 first_page_ = |
969 MemoryAllocator::AllocatePages(requested_pages, &num_pages, this); | 830 Isolate::Current()->memory_allocator()->AllocatePages( |
| 831 requested_pages, &num_pages, this); |
970 if (!first_page_->is_valid()) return false; | 832 if (!first_page_->is_valid()) return false; |
971 } | 833 } |
972 | 834 |
973 // We are sure that the first page is valid and that we have at least one | 835 // We are sure that the first page is valid and that we have at least one |
974 // page. | 836 // page. |
975 ASSERT(first_page_->is_valid()); | 837 ASSERT(first_page_->is_valid()); |
976 ASSERT(num_pages > 0); | 838 ASSERT(num_pages > 0); |
977 accounting_stats_.ExpandSpace(num_pages * Page::kObjectAreaSize); | 839 accounting_stats_.ExpandSpace(num_pages * Page::kObjectAreaSize); |
978 ASSERT(Capacity() <= max_capacity_); | 840 ASSERT(Capacity() <= max_capacity_); |
979 | 841 |
(...skipping 12 matching lines...) Expand all Loading... |
992 return true; | 854 return true; |
993 } | 855 } |
994 | 856 |
995 | 857 |
996 bool PagedSpace::HasBeenSetup() { | 858 bool PagedSpace::HasBeenSetup() { |
997 return (Capacity() > 0); | 859 return (Capacity() > 0); |
998 } | 860 } |
999 | 861 |
1000 | 862 |
1001 void PagedSpace::TearDown() { | 863 void PagedSpace::TearDown() { |
1002 MemoryAllocator::FreeAllPages(this); | 864 Isolate::Current()->memory_allocator()->FreeAllPages(this); |
1003 first_page_ = NULL; | 865 first_page_ = NULL; |
1004 accounting_stats_.Clear(); | 866 accounting_stats_.Clear(); |
1005 } | 867 } |
1006 | 868 |
1007 | 869 |
1008 #ifdef ENABLE_HEAP_PROTECTION | 870 #ifdef ENABLE_HEAP_PROTECTION |
1009 | 871 |
1010 void PagedSpace::Protect() { | 872 void PagedSpace::Protect() { |
1011 Page* page = first_page_; | 873 Page* page = first_page_; |
1012 while (page->is_valid()) { | 874 while (page->is_valid()) { |
1013 MemoryAllocator::ProtectChunkFromPage(page); | 875 Isolate::Current()->memory_allocator()->ProtectChunkFromPage(page); |
1014 page = MemoryAllocator::FindLastPageInSameChunk(page)->next_page(); | 876 page = Isolate::Current()->memory_allocator()-> |
| 877 FindLastPageInSameChunk(page)->next_page(); |
1015 } | 878 } |
1016 } | 879 } |
1017 | 880 |
1018 | 881 |
1019 void PagedSpace::Unprotect() { | 882 void PagedSpace::Unprotect() { |
1020 Page* page = first_page_; | 883 Page* page = first_page_; |
1021 while (page->is_valid()) { | 884 while (page->is_valid()) { |
1022 MemoryAllocator::UnprotectChunkFromPage(page); | 885 Isolate::Current()->memory_allocator()->UnprotectChunkFromPage(page); |
1023 page = MemoryAllocator::FindLastPageInSameChunk(page)->next_page(); | 886 page = Isolate::Current()->memory_allocator()-> |
| 887 FindLastPageInSameChunk(page)->next_page(); |
1024 } | 888 } |
1025 } | 889 } |
1026 | 890 |
1027 #endif | 891 #endif |
1028 | 892 |
1029 | 893 |
1030 void PagedSpace::MarkAllPagesClean() { | 894 void PagedSpace::MarkAllPagesClean() { |
1031 PageIterator it(this, PageIterator::ALL_PAGES); | 895 PageIterator it(this, PageIterator::ALL_PAGES); |
1032 while (it.has_next()) { | 896 while (it.has_next()) { |
1033 it.next()->SetRegionMarks(Page::kAllRegionsCleanMarks); | 897 it.next()->SetRegionMarks(Page::kAllRegionsCleanMarks); |
1034 } | 898 } |
1035 } | 899 } |
1036 | 900 |
1037 | 901 |
1038 MaybeObject* PagedSpace::FindObject(Address addr) { | 902 MaybeObject* PagedSpace::FindObject(Address addr) { |
1039 // Note: this function can only be called before or after mark-compact GC | 903 // Note: this function can only be called before or after mark-compact GC |
1040 // because it accesses map pointers. | 904 // because it accesses map pointers. |
1041 ASSERT(!MarkCompactCollector::in_use()); | 905 ASSERT(!heap()->mark_compact_collector()->in_use()); |
1042 | 906 |
1043 if (!Contains(addr)) return Failure::Exception(); | 907 if (!Contains(addr)) return Failure::Exception(); |
1044 | 908 |
1045 Page* p = Page::FromAddress(addr); | 909 Page* p = Page::FromAddress(addr); |
1046 ASSERT(IsUsed(p)); | 910 ASSERT(IsUsed(p)); |
1047 Address cur = p->ObjectAreaStart(); | 911 Address cur = p->ObjectAreaStart(); |
1048 Address end = p->AllocationTop(); | 912 Address end = p->AllocationTop(); |
1049 while (cur < end) { | 913 while (cur < end) { |
1050 HeapObject* obj = HeapObject::FromAddress(cur); | 914 HeapObject* obj = HeapObject::FromAddress(cur); |
1051 Address next = cur + obj->Size(); | 915 Address next = cur + obj->Size(); |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1151 ASSERT(last_page->is_valid() && !last_page->next_page()->is_valid()); | 1015 ASSERT(last_page->is_valid() && !last_page->next_page()->is_valid()); |
1152 | 1016 |
1153 int available_pages = | 1017 int available_pages = |
1154 static_cast<int>((max_capacity_ - Capacity()) / Page::kObjectAreaSize); | 1018 static_cast<int>((max_capacity_ - Capacity()) / Page::kObjectAreaSize); |
1155 // We don't want to have to handle small chunks near the end so if there are | 1019 // We don't want to have to handle small chunks near the end so if there are |
1156 // not kPagesPerChunk pages available without exceeding the max capacity then | 1020 // not kPagesPerChunk pages available without exceeding the max capacity then |
1157 // act as if memory has run out. | 1021 // act as if memory has run out. |
1158 if (available_pages < MemoryAllocator::kPagesPerChunk) return false; | 1022 if (available_pages < MemoryAllocator::kPagesPerChunk) return false; |
1159 | 1023 |
1160 int desired_pages = Min(available_pages, MemoryAllocator::kPagesPerChunk); | 1024 int desired_pages = Min(available_pages, MemoryAllocator::kPagesPerChunk); |
1161 Page* p = MemoryAllocator::AllocatePages(desired_pages, &desired_pages, this); | 1025 Page* p = heap()->isolate()->memory_allocator()->AllocatePages( |
| 1026 desired_pages, &desired_pages, this); |
1162 if (!p->is_valid()) return false; | 1027 if (!p->is_valid()) return false; |
1163 | 1028 |
1164 accounting_stats_.ExpandSpace(desired_pages * Page::kObjectAreaSize); | 1029 accounting_stats_.ExpandSpace(desired_pages * Page::kObjectAreaSize); |
1165 ASSERT(Capacity() <= max_capacity_); | 1030 ASSERT(Capacity() <= max_capacity_); |
1166 | 1031 |
1167 MemoryAllocator::SetNextPage(last_page, p); | 1032 heap()->isolate()->memory_allocator()->SetNextPage(last_page, p); |
1168 | 1033 |
1169 // Sequentially clear region marks of new pages and and cache the | 1034 // Sequentially clear region marks of new pages and and cache the |
1170 // new last page in the space. | 1035 // new last page in the space. |
1171 while (p->is_valid()) { | 1036 while (p->is_valid()) { |
1172 p->SetRegionMarks(Page::kAllRegionsCleanMarks); | 1037 p->SetRegionMarks(Page::kAllRegionsCleanMarks); |
1173 last_page_ = p; | 1038 last_page_ = p; |
1174 p = p->next_page(); | 1039 p = p->next_page(); |
1175 } | 1040 } |
1176 | 1041 |
1177 return true; | 1042 return true; |
(...skipping 22 matching lines...) Expand all Loading... |
1200 Page* top_page = AllocationTopPage(); | 1065 Page* top_page = AllocationTopPage(); |
1201 ASSERT(top_page->is_valid()); | 1066 ASSERT(top_page->is_valid()); |
1202 | 1067 |
1203 // Count the number of pages we would like to free. | 1068 // Count the number of pages we would like to free. |
1204 int pages_to_free = 0; | 1069 int pages_to_free = 0; |
1205 for (Page* p = top_page->next_page(); p->is_valid(); p = p->next_page()) { | 1070 for (Page* p = top_page->next_page(); p->is_valid(); p = p->next_page()) { |
1206 pages_to_free++; | 1071 pages_to_free++; |
1207 } | 1072 } |
1208 | 1073 |
1209 // Free pages after top_page. | 1074 // Free pages after top_page. |
1210 Page* p = MemoryAllocator::FreePages(top_page->next_page()); | 1075 Page* p = heap()->isolate()->memory_allocator()-> |
1211 MemoryAllocator::SetNextPage(top_page, p); | 1076 FreePages(top_page->next_page()); |
| 1077 heap()->isolate()->memory_allocator()->SetNextPage(top_page, p); |
1212 | 1078 |
1213 // Find out how many pages we failed to free and update last_page_. | 1079 // Find out how many pages we failed to free and update last_page_. |
1214 // Please note pages can only be freed in whole chunks. | 1080 // Please note pages can only be freed in whole chunks. |
1215 last_page_ = top_page; | 1081 last_page_ = top_page; |
1216 for (Page* p = top_page->next_page(); p->is_valid(); p = p->next_page()) { | 1082 for (Page* p = top_page->next_page(); p->is_valid(); p = p->next_page()) { |
1217 pages_to_free--; | 1083 pages_to_free--; |
1218 last_page_ = p; | 1084 last_page_ = p; |
1219 } | 1085 } |
1220 | 1086 |
1221 accounting_stats_.ShrinkSpace(pages_to_free * Page::kObjectAreaSize); | 1087 accounting_stats_.ShrinkSpace(pages_to_free * Page::kObjectAreaSize); |
1222 ASSERT(Capacity() == CountTotalPages() * Page::kObjectAreaSize); | 1088 ASSERT(Capacity() == CountTotalPages() * Page::kObjectAreaSize); |
1223 } | 1089 } |
1224 | 1090 |
1225 | 1091 |
1226 bool PagedSpace::EnsureCapacity(int capacity) { | 1092 bool PagedSpace::EnsureCapacity(int capacity) { |
1227 if (Capacity() >= capacity) return true; | 1093 if (Capacity() >= capacity) return true; |
1228 | 1094 |
1229 // Start from the allocation top and loop to the last page in the space. | 1095 // Start from the allocation top and loop to the last page in the space. |
1230 Page* last_page = AllocationTopPage(); | 1096 Page* last_page = AllocationTopPage(); |
1231 Page* next_page = last_page->next_page(); | 1097 Page* next_page = last_page->next_page(); |
1232 while (next_page->is_valid()) { | 1098 while (next_page->is_valid()) { |
1233 last_page = MemoryAllocator::FindLastPageInSameChunk(next_page); | 1099 last_page = heap()->isolate()->memory_allocator()-> |
| 1100 FindLastPageInSameChunk(next_page); |
1234 next_page = last_page->next_page(); | 1101 next_page = last_page->next_page(); |
1235 } | 1102 } |
1236 | 1103 |
1237 // Expand the space until it has the required capacity or expansion fails. | 1104 // Expand the space until it has the required capacity or expansion fails. |
1238 do { | 1105 do { |
1239 if (!Expand(last_page)) return false; | 1106 if (!Expand(last_page)) return false; |
1240 ASSERT(last_page->next_page()->is_valid()); | 1107 ASSERT(last_page->next_page()->is_valid()); |
1241 last_page = | 1108 last_page = |
1242 MemoryAllocator::FindLastPageInSameChunk(last_page->next_page()); | 1109 heap()->isolate()->memory_allocator()->FindLastPageInSameChunk( |
| 1110 last_page->next_page()); |
1243 } while (Capacity() < capacity); | 1111 } while (Capacity() < capacity); |
1244 | 1112 |
1245 return true; | 1113 return true; |
1246 } | 1114 } |
1247 | 1115 |
1248 | 1116 |
1249 #ifdef DEBUG | 1117 #ifdef DEBUG |
1250 void PagedSpace::Print() { } | 1118 void PagedSpace::Print() { } |
1251 #endif | 1119 #endif |
1252 | 1120 |
1253 | 1121 |
1254 #ifdef DEBUG | 1122 #ifdef DEBUG |
1255 // We do not assume that the PageIterator works, because it depends on the | 1123 // We do not assume that the PageIterator works, because it depends on the |
1256 // invariants we are checking during verification. | 1124 // invariants we are checking during verification. |
1257 void PagedSpace::Verify(ObjectVisitor* visitor) { | 1125 void PagedSpace::Verify(ObjectVisitor* visitor) { |
1258 // The allocation pointer should be valid, and it should be in a page in the | 1126 // The allocation pointer should be valid, and it should be in a page in the |
1259 // space. | 1127 // space. |
1260 ASSERT(allocation_info_.VerifyPagedAllocation()); | 1128 ASSERT(allocation_info_.VerifyPagedAllocation()); |
1261 Page* top_page = Page::FromAllocationTop(allocation_info_.top); | 1129 Page* top_page = Page::FromAllocationTop(allocation_info_.top); |
1262 ASSERT(MemoryAllocator::IsPageInSpace(top_page, this)); | 1130 ASSERT(heap()->isolate()->memory_allocator()->IsPageInSpace(top_page, this)); |
1263 | 1131 |
1264 // Loop over all the pages. | 1132 // Loop over all the pages. |
1265 bool above_allocation_top = false; | 1133 bool above_allocation_top = false; |
1266 Page* current_page = first_page_; | 1134 Page* current_page = first_page_; |
1267 while (current_page->is_valid()) { | 1135 while (current_page->is_valid()) { |
1268 if (above_allocation_top) { | 1136 if (above_allocation_top) { |
1269 // We don't care what's above the allocation top. | 1137 // We don't care what's above the allocation top. |
1270 } else { | 1138 } else { |
1271 Address top = current_page->AllocationTop(); | 1139 Address top = current_page->AllocationTop(); |
1272 if (current_page == top_page) { | 1140 if (current_page == top_page) { |
1273 ASSERT(top == allocation_info_.top); | 1141 ASSERT(top == allocation_info_.top); |
1274 // The next page will be above the allocation top. | 1142 // The next page will be above the allocation top. |
1275 above_allocation_top = true; | 1143 above_allocation_top = true; |
1276 } | 1144 } |
1277 | 1145 |
1278 // It should be packed with objects from the bottom to the top. | 1146 // It should be packed with objects from the bottom to the top. |
1279 Address current = current_page->ObjectAreaStart(); | 1147 Address current = current_page->ObjectAreaStart(); |
1280 while (current < top) { | 1148 while (current < top) { |
1281 HeapObject* object = HeapObject::FromAddress(current); | 1149 HeapObject* object = HeapObject::FromAddress(current); |
1282 | 1150 |
1283 // The first word should be a map, and we expect all map pointers to | 1151 // The first word should be a map, and we expect all map pointers to |
1284 // be in map space. | 1152 // be in map space. |
1285 Map* map = object->map(); | 1153 Map* map = object->map(); |
1286 ASSERT(map->IsMap()); | 1154 ASSERT(map->IsMap()); |
1287 ASSERT(Heap::map_space()->Contains(map)); | 1155 ASSERT(heap()->map_space()->Contains(map)); |
1288 | 1156 |
1289 // Perform space-specific object verification. | 1157 // Perform space-specific object verification. |
1290 VerifyObject(object); | 1158 VerifyObject(object); |
1291 | 1159 |
1292 // The object itself should look OK. | 1160 // The object itself should look OK. |
1293 object->Verify(); | 1161 object->Verify(); |
1294 | 1162 |
1295 // All the interior pointers should be contained in the heap and | 1163 // All the interior pointers should be contained in the heap and |
1296 // have page regions covering intergenerational references should be | 1164 // have page regions covering intergenerational references should be |
1297 // marked dirty. | 1165 // marked dirty. |
(...skipping 15 matching lines...) Expand all Loading... |
1313 | 1181 |
1314 // ----------------------------------------------------------------------------- | 1182 // ----------------------------------------------------------------------------- |
1315 // NewSpace implementation | 1183 // NewSpace implementation |
1316 | 1184 |
1317 | 1185 |
1318 bool NewSpace::Setup(Address start, int size) { | 1186 bool NewSpace::Setup(Address start, int size) { |
1319 // Setup new space based on the preallocated memory block defined by | 1187 // Setup new space based on the preallocated memory block defined by |
1320 // start and size. The provided space is divided into two semi-spaces. | 1188 // start and size. The provided space is divided into two semi-spaces. |
1321 // To support fast containment testing in the new space, the size of | 1189 // To support fast containment testing in the new space, the size of |
1322 // this chunk must be a power of two and it must be aligned to its size. | 1190 // this chunk must be a power of two and it must be aligned to its size. |
1323 int initial_semispace_capacity = Heap::InitialSemiSpaceSize(); | 1191 int initial_semispace_capacity = heap()->InitialSemiSpaceSize(); |
1324 int maximum_semispace_capacity = Heap::MaxSemiSpaceSize(); | 1192 int maximum_semispace_capacity = heap()->MaxSemiSpaceSize(); |
1325 | 1193 |
1326 ASSERT(initial_semispace_capacity <= maximum_semispace_capacity); | 1194 ASSERT(initial_semispace_capacity <= maximum_semispace_capacity); |
1327 ASSERT(IsPowerOf2(maximum_semispace_capacity)); | 1195 ASSERT(IsPowerOf2(maximum_semispace_capacity)); |
1328 | 1196 |
1329 // Allocate and setup the histogram arrays if necessary. | 1197 // Allocate and setup the histogram arrays if necessary. |
1330 #if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING) | 1198 #if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING) |
1331 allocated_histogram_ = NewArray<HistogramInfo>(LAST_TYPE + 1); | 1199 allocated_histogram_ = NewArray<HistogramInfo>(LAST_TYPE + 1); |
1332 promoted_histogram_ = NewArray<HistogramInfo>(LAST_TYPE + 1); | 1200 promoted_histogram_ = NewArray<HistogramInfo>(LAST_TYPE + 1); |
1333 | 1201 |
1334 #define SET_NAME(name) allocated_histogram_[name].set_name(#name); \ | 1202 #define SET_NAME(name) allocated_histogram_[name].set_name(#name); \ |
1335 promoted_histogram_[name].set_name(#name); | 1203 promoted_histogram_[name].set_name(#name); |
1336 INSTANCE_TYPE_LIST(SET_NAME) | 1204 INSTANCE_TYPE_LIST(SET_NAME) |
1337 #undef SET_NAME | 1205 #undef SET_NAME |
1338 #endif | 1206 #endif |
1339 | 1207 |
1340 ASSERT(size == 2 * Heap::ReservedSemiSpaceSize()); | 1208 ASSERT(size == 2 * heap()->ReservedSemiSpaceSize()); |
1341 ASSERT(IsAddressAligned(start, size, 0)); | 1209 ASSERT(IsAddressAligned(start, size, 0)); |
1342 | 1210 |
1343 if (!to_space_.Setup(start, | 1211 if (!to_space_.Setup(start, |
1344 initial_semispace_capacity, | 1212 initial_semispace_capacity, |
1345 maximum_semispace_capacity)) { | 1213 maximum_semispace_capacity)) { |
1346 return false; | 1214 return false; |
1347 } | 1215 } |
1348 if (!from_space_.Setup(start + maximum_semispace_capacity, | 1216 if (!from_space_.Setup(start + maximum_semispace_capacity, |
1349 initial_semispace_capacity, | 1217 initial_semispace_capacity, |
1350 maximum_semispace_capacity)) { | 1218 maximum_semispace_capacity)) { |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1385 mc_forwarding_info_.limit = NULL; | 1253 mc_forwarding_info_.limit = NULL; |
1386 | 1254 |
1387 to_space_.TearDown(); | 1255 to_space_.TearDown(); |
1388 from_space_.TearDown(); | 1256 from_space_.TearDown(); |
1389 } | 1257 } |
1390 | 1258 |
1391 | 1259 |
1392 #ifdef ENABLE_HEAP_PROTECTION | 1260 #ifdef ENABLE_HEAP_PROTECTION |
1393 | 1261 |
1394 void NewSpace::Protect() { | 1262 void NewSpace::Protect() { |
1395 MemoryAllocator::Protect(ToSpaceLow(), Capacity()); | 1263 heap()->isolate()->memory_allocator()->Protect(ToSpaceLow(), Capacity()); |
1396 MemoryAllocator::Protect(FromSpaceLow(), Capacity()); | 1264 heap()->isolate()->memory_allocator()->Protect(FromSpaceLow(), Capacity()); |
1397 } | 1265 } |
1398 | 1266 |
1399 | 1267 |
1400 void NewSpace::Unprotect() { | 1268 void NewSpace::Unprotect() { |
1401 MemoryAllocator::Unprotect(ToSpaceLow(), Capacity(), | 1269 heap()->isolate()->memory_allocator()->Unprotect(ToSpaceLow(), Capacity(), |
1402 to_space_.executable()); | 1270 to_space_.executable()); |
1403 MemoryAllocator::Unprotect(FromSpaceLow(), Capacity(), | 1271 heap()->isolate()->memory_allocator()->Unprotect(FromSpaceLow(), Capacity(), |
1404 from_space_.executable()); | 1272 from_space_.executable()); |
1405 } | 1273 } |
1406 | 1274 |
1407 #endif | 1275 #endif |
1408 | 1276 |
1409 | 1277 |
1410 void NewSpace::Flip() { | 1278 void NewSpace::Flip() { |
1411 SemiSpace tmp = from_space_; | 1279 SemiSpace tmp = from_space_; |
1412 from_space_ = to_space_; | 1280 from_space_ = to_space_; |
1413 to_space_ = tmp; | 1281 to_space_ = tmp; |
1414 } | 1282 } |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1488 // There should be objects packed in from the low address up to the | 1356 // There should be objects packed in from the low address up to the |
1489 // allocation pointer. | 1357 // allocation pointer. |
1490 Address current = to_space_.low(); | 1358 Address current = to_space_.low(); |
1491 while (current < top()) { | 1359 while (current < top()) { |
1492 HeapObject* object = HeapObject::FromAddress(current); | 1360 HeapObject* object = HeapObject::FromAddress(current); |
1493 | 1361 |
1494 // The first word should be a map, and we expect all map pointers to | 1362 // The first word should be a map, and we expect all map pointers to |
1495 // be in map space. | 1363 // be in map space. |
1496 Map* map = object->map(); | 1364 Map* map = object->map(); |
1497 ASSERT(map->IsMap()); | 1365 ASSERT(map->IsMap()); |
1498 ASSERT(Heap::map_space()->Contains(map)); | 1366 ASSERT(heap()->map_space()->Contains(map)); |
1499 | 1367 |
1500 // The object should not be code or a map. | 1368 // The object should not be code or a map. |
1501 ASSERT(!object->IsMap()); | 1369 ASSERT(!object->IsMap()); |
1502 ASSERT(!object->IsCode()); | 1370 ASSERT(!object->IsCode()); |
1503 | 1371 |
1504 // The object itself should look OK. | 1372 // The object itself should look OK. |
1505 object->Verify(); | 1373 object->Verify(); |
1506 | 1374 |
1507 // All the interior pointers should be contained in the heap. | 1375 // All the interior pointers should be contained in the heap. |
1508 VerifyPointersVisitor visitor; | 1376 VerifyPointersVisitor visitor; |
1509 int size = object->Size(); | 1377 int size = object->Size(); |
1510 object->IterateBody(map->instance_type(), size, &visitor); | 1378 object->IterateBody(map->instance_type(), size, &visitor); |
1511 | 1379 |
1512 current += size; | 1380 current += size; |
1513 } | 1381 } |
1514 | 1382 |
1515 // The allocation pointer should not be in the middle of an object. | 1383 // The allocation pointer should not be in the middle of an object. |
1516 ASSERT(current == top()); | 1384 ASSERT(current == top()); |
1517 } | 1385 } |
1518 #endif | 1386 #endif |
1519 | 1387 |
1520 | 1388 |
1521 bool SemiSpace::Commit() { | 1389 bool SemiSpace::Commit() { |
1522 ASSERT(!is_committed()); | 1390 ASSERT(!is_committed()); |
1523 if (!MemoryAllocator::CommitBlock(start_, capacity_, executable())) { | 1391 if (!heap()->isolate()->memory_allocator()->CommitBlock( |
| 1392 start_, capacity_, executable())) { |
1524 return false; | 1393 return false; |
1525 } | 1394 } |
1526 committed_ = true; | 1395 committed_ = true; |
1527 return true; | 1396 return true; |
1528 } | 1397 } |
1529 | 1398 |
1530 | 1399 |
1531 bool SemiSpace::Uncommit() { | 1400 bool SemiSpace::Uncommit() { |
1532 ASSERT(is_committed()); | 1401 ASSERT(is_committed()); |
1533 if (!MemoryAllocator::UncommitBlock(start_, capacity_)) { | 1402 if (!heap()->isolate()->memory_allocator()->UncommitBlock( |
| 1403 start_, capacity_)) { |
1534 return false; | 1404 return false; |
1535 } | 1405 } |
1536 committed_ = false; | 1406 committed_ = false; |
1537 return true; | 1407 return true; |
1538 } | 1408 } |
1539 | 1409 |
1540 | 1410 |
1541 // ----------------------------------------------------------------------------- | 1411 // ----------------------------------------------------------------------------- |
1542 // SemiSpace implementation | 1412 // SemiSpace implementation |
1543 | 1413 |
(...skipping 25 matching lines...) Expand all Loading... |
1569 start_ = NULL; | 1439 start_ = NULL; |
1570 capacity_ = 0; | 1440 capacity_ = 0; |
1571 } | 1441 } |
1572 | 1442 |
1573 | 1443 |
1574 bool SemiSpace::Grow() { | 1444 bool SemiSpace::Grow() { |
1575 // Double the semispace size but only up to maximum capacity. | 1445 // Double the semispace size but only up to maximum capacity. |
1576 int maximum_extra = maximum_capacity_ - capacity_; | 1446 int maximum_extra = maximum_capacity_ - capacity_; |
1577 int extra = Min(RoundUp(capacity_, static_cast<int>(OS::AllocateAlignment())), | 1447 int extra = Min(RoundUp(capacity_, static_cast<int>(OS::AllocateAlignment())), |
1578 maximum_extra); | 1448 maximum_extra); |
1579 if (!MemoryAllocator::CommitBlock(high(), extra, executable())) { | 1449 if (!heap()->isolate()->memory_allocator()->CommitBlock( |
| 1450 high(), extra, executable())) { |
1580 return false; | 1451 return false; |
1581 } | 1452 } |
1582 capacity_ += extra; | 1453 capacity_ += extra; |
1583 return true; | 1454 return true; |
1584 } | 1455 } |
1585 | 1456 |
1586 | 1457 |
1587 bool SemiSpace::GrowTo(int new_capacity) { | 1458 bool SemiSpace::GrowTo(int new_capacity) { |
1588 ASSERT(new_capacity <= maximum_capacity_); | 1459 ASSERT(new_capacity <= maximum_capacity_); |
1589 ASSERT(new_capacity > capacity_); | 1460 ASSERT(new_capacity > capacity_); |
1590 size_t delta = new_capacity - capacity_; | 1461 size_t delta = new_capacity - capacity_; |
1591 ASSERT(IsAligned(delta, OS::AllocateAlignment())); | 1462 ASSERT(IsAligned(delta, OS::AllocateAlignment())); |
1592 if (!MemoryAllocator::CommitBlock(high(), delta, executable())) { | 1463 if (!heap()->isolate()->memory_allocator()->CommitBlock( |
| 1464 high(), delta, executable())) { |
1593 return false; | 1465 return false; |
1594 } | 1466 } |
1595 capacity_ = new_capacity; | 1467 capacity_ = new_capacity; |
1596 return true; | 1468 return true; |
1597 } | 1469 } |
1598 | 1470 |
1599 | 1471 |
1600 bool SemiSpace::ShrinkTo(int new_capacity) { | 1472 bool SemiSpace::ShrinkTo(int new_capacity) { |
1601 ASSERT(new_capacity >= initial_capacity_); | 1473 ASSERT(new_capacity >= initial_capacity_); |
1602 ASSERT(new_capacity < capacity_); | 1474 ASSERT(new_capacity < capacity_); |
1603 size_t delta = capacity_ - new_capacity; | 1475 size_t delta = capacity_ - new_capacity; |
1604 ASSERT(IsAligned(delta, OS::AllocateAlignment())); | 1476 ASSERT(IsAligned(delta, OS::AllocateAlignment())); |
1605 if (!MemoryAllocator::UncommitBlock(high() - delta, delta)) { | 1477 if (!heap()->isolate()->memory_allocator()->UncommitBlock( |
| 1478 high() - delta, delta)) { |
1606 return false; | 1479 return false; |
1607 } | 1480 } |
1608 capacity_ = new_capacity; | 1481 capacity_ = new_capacity; |
1609 return true; | 1482 return true; |
1610 } | 1483 } |
1611 | 1484 |
1612 | 1485 |
1613 #ifdef DEBUG | 1486 #ifdef DEBUG |
1614 void SemiSpace::Print() { } | 1487 void SemiSpace::Print() { } |
1615 | 1488 |
(...skipping 27 matching lines...) Expand all Loading... |
1643 ASSERT(space->ToSpaceLow() <= end | 1516 ASSERT(space->ToSpaceLow() <= end |
1644 && end <= space->ToSpaceHigh()); | 1517 && end <= space->ToSpaceHigh()); |
1645 space_ = &space->to_space_; | 1518 space_ = &space->to_space_; |
1646 current_ = start; | 1519 current_ = start; |
1647 limit_ = end; | 1520 limit_ = end; |
1648 size_func_ = size_func; | 1521 size_func_ = size_func; |
1649 } | 1522 } |
1650 | 1523 |
1651 | 1524 |
1652 #ifdef DEBUG | 1525 #ifdef DEBUG |
1653 // A static array of histogram info for each type. | |
1654 static HistogramInfo heap_histograms[LAST_TYPE+1]; | |
1655 static JSObject::SpillInformation js_spill_information; | |
1656 | |
1657 // heap_histograms is shared, always clear it before using it. | 1526 // heap_histograms is shared, always clear it before using it. |
1658 static void ClearHistograms() { | 1527 static void ClearHistograms() { |
| 1528 Isolate* isolate = Isolate::Current(); |
1659 // We reset the name each time, though it hasn't changed. | 1529 // We reset the name each time, though it hasn't changed. |
1660 #define DEF_TYPE_NAME(name) heap_histograms[name].set_name(#name); | 1530 #define DEF_TYPE_NAME(name) isolate->heap_histograms()[name].set_name(#name); |
1661 INSTANCE_TYPE_LIST(DEF_TYPE_NAME) | 1531 INSTANCE_TYPE_LIST(DEF_TYPE_NAME) |
1662 #undef DEF_TYPE_NAME | 1532 #undef DEF_TYPE_NAME |
1663 | 1533 |
1664 #define CLEAR_HISTOGRAM(name) heap_histograms[name].clear(); | 1534 #define CLEAR_HISTOGRAM(name) isolate->heap_histograms()[name].clear(); |
1665 INSTANCE_TYPE_LIST(CLEAR_HISTOGRAM) | 1535 INSTANCE_TYPE_LIST(CLEAR_HISTOGRAM) |
1666 #undef CLEAR_HISTOGRAM | 1536 #undef CLEAR_HISTOGRAM |
1667 | 1537 |
1668 js_spill_information.Clear(); | 1538 isolate->js_spill_information()->Clear(); |
1669 } | 1539 } |
1670 | 1540 |
1671 | 1541 |
1672 static int code_kind_statistics[Code::NUMBER_OF_KINDS]; | |
1673 | |
1674 | |
1675 static void ClearCodeKindStatistics() { | 1542 static void ClearCodeKindStatistics() { |
| 1543 Isolate* isolate = Isolate::Current(); |
1676 for (int i = 0; i < Code::NUMBER_OF_KINDS; i++) { | 1544 for (int i = 0; i < Code::NUMBER_OF_KINDS; i++) { |
1677 code_kind_statistics[i] = 0; | 1545 isolate->code_kind_statistics()[i] = 0; |
1678 } | 1546 } |
1679 } | 1547 } |
1680 | 1548 |
1681 | 1549 |
1682 static void ReportCodeKindStatistics() { | 1550 static void ReportCodeKindStatistics() { |
| 1551 Isolate* isolate = Isolate::Current(); |
1683 const char* table[Code::NUMBER_OF_KINDS] = { NULL }; | 1552 const char* table[Code::NUMBER_OF_KINDS] = { NULL }; |
1684 | 1553 |
1685 #define CASE(name) \ | 1554 #define CASE(name) \ |
1686 case Code::name: table[Code::name] = #name; \ | 1555 case Code::name: table[Code::name] = #name; \ |
1687 break | 1556 break |
1688 | 1557 |
1689 for (int i = 0; i < Code::NUMBER_OF_KINDS; i++) { | 1558 for (int i = 0; i < Code::NUMBER_OF_KINDS; i++) { |
1690 switch (static_cast<Code::Kind>(i)) { | 1559 switch (static_cast<Code::Kind>(i)) { |
1691 CASE(FUNCTION); | 1560 CASE(FUNCTION); |
1692 CASE(OPTIMIZED_FUNCTION); | 1561 CASE(OPTIMIZED_FUNCTION); |
(...skipping 10 matching lines...) Expand all Loading... |
1703 CASE(BINARY_OP_IC); | 1572 CASE(BINARY_OP_IC); |
1704 CASE(TYPE_RECORDING_BINARY_OP_IC); | 1573 CASE(TYPE_RECORDING_BINARY_OP_IC); |
1705 CASE(COMPARE_IC); | 1574 CASE(COMPARE_IC); |
1706 } | 1575 } |
1707 } | 1576 } |
1708 | 1577 |
1709 #undef CASE | 1578 #undef CASE |
1710 | 1579 |
1711 PrintF("\n Code kind histograms: \n"); | 1580 PrintF("\n Code kind histograms: \n"); |
1712 for (int i = 0; i < Code::NUMBER_OF_KINDS; i++) { | 1581 for (int i = 0; i < Code::NUMBER_OF_KINDS; i++) { |
1713 if (code_kind_statistics[i] > 0) { | 1582 if (isolate->code_kind_statistics()[i] > 0) { |
1714 PrintF(" %-20s: %10d bytes\n", table[i], code_kind_statistics[i]); | 1583 PrintF(" %-20s: %10d bytes\n", table[i], |
| 1584 isolate->code_kind_statistics()[i]); |
1715 } | 1585 } |
1716 } | 1586 } |
1717 PrintF("\n"); | 1587 PrintF("\n"); |
1718 } | 1588 } |
1719 | 1589 |
1720 | 1590 |
1721 static int CollectHistogramInfo(HeapObject* obj) { | 1591 static int CollectHistogramInfo(HeapObject* obj) { |
| 1592 Isolate* isolate = Isolate::Current(); |
1722 InstanceType type = obj->map()->instance_type(); | 1593 InstanceType type = obj->map()->instance_type(); |
1723 ASSERT(0 <= type && type <= LAST_TYPE); | 1594 ASSERT(0 <= type && type <= LAST_TYPE); |
1724 ASSERT(heap_histograms[type].name() != NULL); | 1595 ASSERT(isolate->heap_histograms()[type].name() != NULL); |
1725 heap_histograms[type].increment_number(1); | 1596 isolate->heap_histograms()[type].increment_number(1); |
1726 heap_histograms[type].increment_bytes(obj->Size()); | 1597 isolate->heap_histograms()[type].increment_bytes(obj->Size()); |
1727 | 1598 |
1728 if (FLAG_collect_heap_spill_statistics && obj->IsJSObject()) { | 1599 if (FLAG_collect_heap_spill_statistics && obj->IsJSObject()) { |
1729 JSObject::cast(obj)->IncrementSpillStatistics(&js_spill_information); | 1600 JSObject::cast(obj)->IncrementSpillStatistics( |
| 1601 isolate->js_spill_information()); |
1730 } | 1602 } |
1731 | 1603 |
1732 return obj->Size(); | 1604 return obj->Size(); |
1733 } | 1605 } |
1734 | 1606 |
1735 | 1607 |
1736 static void ReportHistogram(bool print_spill) { | 1608 static void ReportHistogram(bool print_spill) { |
| 1609 Isolate* isolate = Isolate::Current(); |
1737 PrintF("\n Object Histogram:\n"); | 1610 PrintF("\n Object Histogram:\n"); |
1738 for (int i = 0; i <= LAST_TYPE; i++) { | 1611 for (int i = 0; i <= LAST_TYPE; i++) { |
1739 if (heap_histograms[i].number() > 0) { | 1612 if (isolate->heap_histograms()[i].number() > 0) { |
1740 PrintF(" %-34s%10d (%10d bytes)\n", | 1613 PrintF(" %-34s%10d (%10d bytes)\n", |
1741 heap_histograms[i].name(), | 1614 isolate->heap_histograms()[i].name(), |
1742 heap_histograms[i].number(), | 1615 isolate->heap_histograms()[i].number(), |
1743 heap_histograms[i].bytes()); | 1616 isolate->heap_histograms()[i].bytes()); |
1744 } | 1617 } |
1745 } | 1618 } |
1746 PrintF("\n"); | 1619 PrintF("\n"); |
1747 | 1620 |
1748 // Summarize string types. | 1621 // Summarize string types. |
1749 int string_number = 0; | 1622 int string_number = 0; |
1750 int string_bytes = 0; | 1623 int string_bytes = 0; |
1751 #define INCREMENT(type, size, name, camel_name) \ | 1624 #define INCREMENT(type, size, name, camel_name) \ |
1752 string_number += heap_histograms[type].number(); \ | 1625 string_number += isolate->heap_histograms()[type].number(); \ |
1753 string_bytes += heap_histograms[type].bytes(); | 1626 string_bytes += isolate->heap_histograms()[type].bytes(); |
1754 STRING_TYPE_LIST(INCREMENT) | 1627 STRING_TYPE_LIST(INCREMENT) |
1755 #undef INCREMENT | 1628 #undef INCREMENT |
1756 if (string_number > 0) { | 1629 if (string_number > 0) { |
1757 PrintF(" %-34s%10d (%10d bytes)\n\n", "STRING_TYPE", string_number, | 1630 PrintF(" %-34s%10d (%10d bytes)\n\n", "STRING_TYPE", string_number, |
1758 string_bytes); | 1631 string_bytes); |
1759 } | 1632 } |
1760 | 1633 |
1761 if (FLAG_collect_heap_spill_statistics && print_spill) { | 1634 if (FLAG_collect_heap_spill_statistics && print_spill) { |
1762 js_spill_information.Print(); | 1635 isolate->js_spill_information()->Print(); |
1763 } | 1636 } |
1764 } | 1637 } |
1765 #endif // DEBUG | 1638 #endif // DEBUG |
1766 | 1639 |
1767 | 1640 |
1768 // Support for statistics gathering for --heap-stats and --log-gc. | 1641 // Support for statistics gathering for --heap-stats and --log-gc. |
1769 #if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING) | 1642 #if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING) |
1770 void NewSpace::ClearHistograms() { | 1643 void NewSpace::ClearHistograms() { |
1771 for (int i = 0; i <= LAST_TYPE; i++) { | 1644 for (int i = 0; i <= LAST_TYPE; i++) { |
1772 allocated_histogram_[i].clear(); | 1645 allocated_histogram_[i].clear(); |
1773 promoted_histogram_[i].clear(); | 1646 promoted_histogram_[i].clear(); |
1774 } | 1647 } |
1775 } | 1648 } |
1776 | 1649 |
1777 // Because the copying collector does not touch garbage objects, we iterate | 1650 // Because the copying collector does not touch garbage objects, we iterate |
1778 // the new space before a collection to get a histogram of allocated objects. | 1651 // the new space before a collection to get a histogram of allocated objects. |
1779 // This only happens (1) when compiled with DEBUG and the --heap-stats flag is | 1652 // This only happens (1) when compiled with DEBUG and the --heap-stats flag is |
1780 // set, or when compiled with ENABLE_LOGGING_AND_PROFILING and the --log-gc | 1653 // set, or when compiled with ENABLE_LOGGING_AND_PROFILING and the --log-gc |
1781 // flag is set. | 1654 // flag is set. |
1782 void NewSpace::CollectStatistics() { | 1655 void NewSpace::CollectStatistics() { |
1783 ClearHistograms(); | 1656 ClearHistograms(); |
1784 SemiSpaceIterator it(this); | 1657 SemiSpaceIterator it(this); |
1785 for (HeapObject* obj = it.next(); obj != NULL; obj = it.next()) | 1658 for (HeapObject* obj = it.next(); obj != NULL; obj = it.next()) |
1786 RecordAllocation(obj); | 1659 RecordAllocation(obj); |
1787 } | 1660 } |
1788 | 1661 |
1789 | 1662 |
1790 #ifdef ENABLE_LOGGING_AND_PROFILING | 1663 #ifdef ENABLE_LOGGING_AND_PROFILING |
1791 static void DoReportStatistics(HistogramInfo* info, const char* description) { | 1664 static void DoReportStatistics(Isolate* isolate, |
1792 LOG(HeapSampleBeginEvent("NewSpace", description)); | 1665 HistogramInfo* info, const char* description) { |
| 1666 LOG(isolate, HeapSampleBeginEvent("NewSpace", description)); |
1793 // Lump all the string types together. | 1667 // Lump all the string types together. |
1794 int string_number = 0; | 1668 int string_number = 0; |
1795 int string_bytes = 0; | 1669 int string_bytes = 0; |
1796 #define INCREMENT(type, size, name, camel_name) \ | 1670 #define INCREMENT(type, size, name, camel_name) \ |
1797 string_number += info[type].number(); \ | 1671 string_number += info[type].number(); \ |
1798 string_bytes += info[type].bytes(); | 1672 string_bytes += info[type].bytes(); |
1799 STRING_TYPE_LIST(INCREMENT) | 1673 STRING_TYPE_LIST(INCREMENT) |
1800 #undef INCREMENT | 1674 #undef INCREMENT |
1801 if (string_number > 0) { | 1675 if (string_number > 0) { |
1802 LOG(HeapSampleItemEvent("STRING_TYPE", string_number, string_bytes)); | 1676 LOG(isolate, |
| 1677 HeapSampleItemEvent("STRING_TYPE", string_number, string_bytes)); |
1803 } | 1678 } |
1804 | 1679 |
1805 // Then do the other types. | 1680 // Then do the other types. |
1806 for (int i = FIRST_NONSTRING_TYPE; i <= LAST_TYPE; ++i) { | 1681 for (int i = FIRST_NONSTRING_TYPE; i <= LAST_TYPE; ++i) { |
1807 if (info[i].number() > 0) { | 1682 if (info[i].number() > 0) { |
1808 LOG(HeapSampleItemEvent(info[i].name(), info[i].number(), | 1683 LOG(isolate, |
| 1684 HeapSampleItemEvent(info[i].name(), info[i].number(), |
1809 info[i].bytes())); | 1685 info[i].bytes())); |
1810 } | 1686 } |
1811 } | 1687 } |
1812 LOG(HeapSampleEndEvent("NewSpace", description)); | 1688 LOG(isolate, HeapSampleEndEvent("NewSpace", description)); |
1813 } | 1689 } |
1814 #endif // ENABLE_LOGGING_AND_PROFILING | 1690 #endif // ENABLE_LOGGING_AND_PROFILING |
1815 | 1691 |
1816 | 1692 |
1817 void NewSpace::ReportStatistics() { | 1693 void NewSpace::ReportStatistics() { |
1818 #ifdef DEBUG | 1694 #ifdef DEBUG |
1819 if (FLAG_heap_stats) { | 1695 if (FLAG_heap_stats) { |
1820 float pct = static_cast<float>(Available()) / Capacity(); | 1696 float pct = static_cast<float>(Available()) / Capacity(); |
1821 PrintF(" capacity: %" V8_PTR_PREFIX "d" | 1697 PrintF(" capacity: %" V8_PTR_PREFIX "d" |
1822 ", available: %" V8_PTR_PREFIX "d, %%%d\n", | 1698 ", available: %" V8_PTR_PREFIX "d, %%%d\n", |
1823 Capacity(), Available(), static_cast<int>(pct*100)); | 1699 Capacity(), Available(), static_cast<int>(pct*100)); |
1824 PrintF("\n Object Histogram:\n"); | 1700 PrintF("\n Object Histogram:\n"); |
1825 for (int i = 0; i <= LAST_TYPE; i++) { | 1701 for (int i = 0; i <= LAST_TYPE; i++) { |
1826 if (allocated_histogram_[i].number() > 0) { | 1702 if (allocated_histogram_[i].number() > 0) { |
1827 PrintF(" %-34s%10d (%10d bytes)\n", | 1703 PrintF(" %-34s%10d (%10d bytes)\n", |
1828 allocated_histogram_[i].name(), | 1704 allocated_histogram_[i].name(), |
1829 allocated_histogram_[i].number(), | 1705 allocated_histogram_[i].number(), |
1830 allocated_histogram_[i].bytes()); | 1706 allocated_histogram_[i].bytes()); |
1831 } | 1707 } |
1832 } | 1708 } |
1833 PrintF("\n"); | 1709 PrintF("\n"); |
1834 } | 1710 } |
1835 #endif // DEBUG | 1711 #endif // DEBUG |
1836 | 1712 |
1837 #ifdef ENABLE_LOGGING_AND_PROFILING | 1713 #ifdef ENABLE_LOGGING_AND_PROFILING |
1838 if (FLAG_log_gc) { | 1714 if (FLAG_log_gc) { |
1839 DoReportStatistics(allocated_histogram_, "allocated"); | 1715 Isolate* isolate = ISOLATE; |
1840 DoReportStatistics(promoted_histogram_, "promoted"); | 1716 DoReportStatistics(isolate, allocated_histogram_, "allocated"); |
| 1717 DoReportStatistics(isolate, promoted_histogram_, "promoted"); |
1841 } | 1718 } |
1842 #endif // ENABLE_LOGGING_AND_PROFILING | 1719 #endif // ENABLE_LOGGING_AND_PROFILING |
1843 } | 1720 } |
1844 | 1721 |
1845 | 1722 |
1846 void NewSpace::RecordAllocation(HeapObject* obj) { | 1723 void NewSpace::RecordAllocation(HeapObject* obj) { |
1847 InstanceType type = obj->map()->instance_type(); | 1724 InstanceType type = obj->map()->instance_type(); |
1848 ASSERT(0 <= type && type <= LAST_TYPE); | 1725 ASSERT(0 <= type && type <= LAST_TYPE); |
1849 allocated_histogram_[type].increment_number(1); | 1726 allocated_histogram_[type].increment_number(1); |
1850 allocated_histogram_[type].increment_bytes(obj->Size()); | 1727 allocated_histogram_[type].increment_bytes(obj->Size()); |
(...skipping 17 matching lines...) Expand all Loading... |
1868 ASSERT(IsAligned(size_in_bytes, kPointerSize)); | 1745 ASSERT(IsAligned(size_in_bytes, kPointerSize)); |
1869 | 1746 |
1870 // We write a map and possibly size information to the block. If the block | 1747 // We write a map and possibly size information to the block. If the block |
1871 // is big enough to be a ByteArray with at least one extra word (the next | 1748 // is big enough to be a ByteArray with at least one extra word (the next |
1872 // pointer), we set its map to be the byte array map and its size to an | 1749 // pointer), we set its map to be the byte array map and its size to an |
1873 // appropriate array length for the desired size from HeapObject::Size(). | 1750 // appropriate array length for the desired size from HeapObject::Size(). |
1874 // If the block is too small (eg, one or two words), to hold both a size | 1751 // If the block is too small (eg, one or two words), to hold both a size |
1875 // field and a next pointer, we give it a filler map that gives it the | 1752 // field and a next pointer, we give it a filler map that gives it the |
1876 // correct size. | 1753 // correct size. |
1877 if (size_in_bytes > ByteArray::kHeaderSize) { | 1754 if (size_in_bytes > ByteArray::kHeaderSize) { |
1878 set_map(Heap::raw_unchecked_byte_array_map()); | 1755 set_map(HEAP->raw_unchecked_byte_array_map()); |
1879 // Can't use ByteArray::cast because it fails during deserialization. | 1756 // Can't use ByteArray::cast because it fails during deserialization. |
1880 ByteArray* this_as_byte_array = reinterpret_cast<ByteArray*>(this); | 1757 ByteArray* this_as_byte_array = reinterpret_cast<ByteArray*>(this); |
1881 this_as_byte_array->set_length(ByteArray::LengthFor(size_in_bytes)); | 1758 this_as_byte_array->set_length(ByteArray::LengthFor(size_in_bytes)); |
1882 } else if (size_in_bytes == kPointerSize) { | 1759 } else if (size_in_bytes == kPointerSize) { |
1883 set_map(Heap::raw_unchecked_one_pointer_filler_map()); | 1760 set_map(HEAP->raw_unchecked_one_pointer_filler_map()); |
1884 } else if (size_in_bytes == 2 * kPointerSize) { | 1761 } else if (size_in_bytes == 2 * kPointerSize) { |
1885 set_map(Heap::raw_unchecked_two_pointer_filler_map()); | 1762 set_map(HEAP->raw_unchecked_two_pointer_filler_map()); |
1886 } else { | 1763 } else { |
1887 UNREACHABLE(); | 1764 UNREACHABLE(); |
1888 } | 1765 } |
1889 // We would like to ASSERT(Size() == size_in_bytes) but this would fail during | 1766 // We would like to ASSERT(Size() == size_in_bytes) but this would fail during |
1890 // deserialization because the byte array map is not done yet. | 1767 // deserialization because the byte array map is not done yet. |
1891 } | 1768 } |
1892 | 1769 |
1893 | 1770 |
1894 Address FreeListNode::next() { | 1771 Address FreeListNode::next() { |
1895 ASSERT(IsFreeListNode(this)); | 1772 ASSERT(IsFreeListNode(this)); |
1896 if (map() == Heap::raw_unchecked_byte_array_map()) { | 1773 if (map() == HEAP->raw_unchecked_byte_array_map()) { |
1897 ASSERT(Size() >= kNextOffset + kPointerSize); | 1774 ASSERT(Size() >= kNextOffset + kPointerSize); |
1898 return Memory::Address_at(address() + kNextOffset); | 1775 return Memory::Address_at(address() + kNextOffset); |
1899 } else { | 1776 } else { |
1900 return Memory::Address_at(address() + kPointerSize); | 1777 return Memory::Address_at(address() + kPointerSize); |
1901 } | 1778 } |
1902 } | 1779 } |
1903 | 1780 |
1904 | 1781 |
1905 void FreeListNode::set_next(Address next) { | 1782 void FreeListNode::set_next(Address next) { |
1906 ASSERT(IsFreeListNode(this)); | 1783 ASSERT(IsFreeListNode(this)); |
1907 if (map() == Heap::raw_unchecked_byte_array_map()) { | 1784 if (map() == HEAP->raw_unchecked_byte_array_map()) { |
1908 ASSERT(Size() >= kNextOffset + kPointerSize); | 1785 ASSERT(Size() >= kNextOffset + kPointerSize); |
1909 Memory::Address_at(address() + kNextOffset) = next; | 1786 Memory::Address_at(address() + kNextOffset) = next; |
1910 } else { | 1787 } else { |
1911 Memory::Address_at(address() + kPointerSize) = next; | 1788 Memory::Address_at(address() + kPointerSize) = next; |
1912 } | 1789 } |
1913 } | 1790 } |
1914 | 1791 |
1915 | 1792 |
1916 OldSpaceFreeList::OldSpaceFreeList(AllocationSpace owner) : owner_(owner) { | 1793 OldSpaceFreeList::OldSpaceFreeList(AllocationSpace owner) : owner_(owner) { |
1917 Reset(); | 1794 Reset(); |
(...skipping 20 matching lines...) Expand all Loading... |
1938 cur = i; | 1815 cur = i; |
1939 } | 1816 } |
1940 } | 1817 } |
1941 free_[cur].next_size_ = kEnd; | 1818 free_[cur].next_size_ = kEnd; |
1942 needs_rebuild_ = false; | 1819 needs_rebuild_ = false; |
1943 } | 1820 } |
1944 | 1821 |
1945 | 1822 |
1946 int OldSpaceFreeList::Free(Address start, int size_in_bytes) { | 1823 int OldSpaceFreeList::Free(Address start, int size_in_bytes) { |
1947 #ifdef DEBUG | 1824 #ifdef DEBUG |
1948 MemoryAllocator::ZapBlock(start, size_in_bytes); | 1825 Isolate::Current()->memory_allocator()->ZapBlock(start, size_in_bytes); |
1949 #endif | 1826 #endif |
1950 FreeListNode* node = FreeListNode::FromAddress(start); | 1827 FreeListNode* node = FreeListNode::FromAddress(start); |
1951 node->set_size(size_in_bytes); | 1828 node->set_size(size_in_bytes); |
1952 | 1829 |
1953 // We don't use the freelists in compacting mode. This makes it more like a | 1830 // We don't use the freelists in compacting mode. This makes it more like a |
1954 // GC that only has mark-sweep-compact and doesn't have a mark-sweep | 1831 // GC that only has mark-sweep-compact and doesn't have a mark-sweep |
1955 // collector. | 1832 // collector. |
1956 if (FLAG_always_compact) { | 1833 if (FLAG_always_compact) { |
1957 return size_in_bytes; | 1834 return size_in_bytes; |
1958 } | 1835 } |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2082 | 1959 |
2083 | 1960 |
2084 void FixedSizeFreeList::Reset() { | 1961 void FixedSizeFreeList::Reset() { |
2085 available_ = 0; | 1962 available_ = 0; |
2086 head_ = tail_ = NULL; | 1963 head_ = tail_ = NULL; |
2087 } | 1964 } |
2088 | 1965 |
2089 | 1966 |
2090 void FixedSizeFreeList::Free(Address start) { | 1967 void FixedSizeFreeList::Free(Address start) { |
2091 #ifdef DEBUG | 1968 #ifdef DEBUG |
2092 MemoryAllocator::ZapBlock(start, object_size_); | 1969 Isolate::Current()->memory_allocator()->ZapBlock(start, object_size_); |
2093 #endif | 1970 #endif |
2094 // We only use the freelists with mark-sweep. | 1971 // We only use the freelists with mark-sweep. |
2095 ASSERT(!MarkCompactCollector::IsCompacting()); | 1972 ASSERT(!HEAP->mark_compact_collector()->IsCompacting()); |
2096 FreeListNode* node = FreeListNode::FromAddress(start); | 1973 FreeListNode* node = FreeListNode::FromAddress(start); |
2097 node->set_size(object_size_); | 1974 node->set_size(object_size_); |
2098 node->set_next(NULL); | 1975 node->set_next(NULL); |
2099 if (head_ == NULL) { | 1976 if (head_ == NULL) { |
2100 tail_ = head_ = node->address(); | 1977 tail_ = head_ = node->address(); |
2101 } else { | 1978 } else { |
2102 FreeListNode::FromAddress(tail_)->set_next(node->address()); | 1979 FreeListNode::FromAddress(tail_)->set_next(node->address()); |
2103 tail_ = node->address(); | 1980 tail_ = node->address(); |
2104 } | 1981 } |
2105 available_ += object_size_; | 1982 available_ += object_size_; |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2212 } | 2089 } |
2213 | 2090 |
2214 Page* first = NULL; | 2091 Page* first = NULL; |
2215 | 2092 |
2216 // Remove pages from the list. | 2093 // Remove pages from the list. |
2217 if (prev == NULL) { | 2094 if (prev == NULL) { |
2218 first = first_page_; | 2095 first = first_page_; |
2219 first_page_ = last->next_page(); | 2096 first_page_ = last->next_page(); |
2220 } else { | 2097 } else { |
2221 first = prev->next_page(); | 2098 first = prev->next_page(); |
2222 MemoryAllocator::SetNextPage(prev, last->next_page()); | 2099 heap()->isolate()->memory_allocator()->SetNextPage( |
| 2100 prev, last->next_page()); |
2223 } | 2101 } |
2224 | 2102 |
2225 // Attach it after the last page. | 2103 // Attach it after the last page. |
2226 MemoryAllocator::SetNextPage(last_page_, first); | 2104 heap()->isolate()->memory_allocator()->SetNextPage(last_page_, first); |
2227 last_page_ = last; | 2105 last_page_ = last; |
2228 MemoryAllocator::SetNextPage(last, NULL); | 2106 heap()->isolate()->memory_allocator()->SetNextPage(last, NULL); |
2229 | 2107 |
2230 // Clean them up. | 2108 // Clean them up. |
2231 do { | 2109 do { |
2232 first->InvalidateWatermark(true); | 2110 first->InvalidateWatermark(true); |
2233 first->SetAllocationWatermark(first->ObjectAreaStart()); | 2111 first->SetAllocationWatermark(first->ObjectAreaStart()); |
2234 first->SetCachedAllocationWatermark(first->ObjectAreaStart()); | 2112 first->SetCachedAllocationWatermark(first->ObjectAreaStart()); |
2235 first->SetRegionMarks(Page::kAllRegionsCleanMarks); | 2113 first->SetRegionMarks(Page::kAllRegionsCleanMarks); |
2236 first = first->next_page(); | 2114 first = first->next_page(); |
2237 } while (first != NULL); | 2115 } while (first != NULL); |
2238 | 2116 |
(...skipping 18 matching lines...) Expand all Loading... |
2257 if (p == last_in_use) { | 2135 if (p == last_in_use) { |
2258 // We passed a page containing allocation top. All consequent | 2136 // We passed a page containing allocation top. All consequent |
2259 // pages are not used. | 2137 // pages are not used. |
2260 in_use = false; | 2138 in_use = false; |
2261 } | 2139 } |
2262 } | 2140 } |
2263 | 2141 |
2264 if (page_list_is_chunk_ordered_) return; | 2142 if (page_list_is_chunk_ordered_) return; |
2265 | 2143 |
2266 Page* new_last_in_use = Page::FromAddress(NULL); | 2144 Page* new_last_in_use = Page::FromAddress(NULL); |
2267 MemoryAllocator::RelinkPageListInChunkOrder(this, | 2145 heap()->isolate()->memory_allocator()->RelinkPageListInChunkOrder( |
2268 &first_page_, | 2146 this, &first_page_, &last_page_, &new_last_in_use); |
2269 &last_page_, | |
2270 &new_last_in_use); | |
2271 ASSERT(new_last_in_use->is_valid()); | 2147 ASSERT(new_last_in_use->is_valid()); |
2272 | 2148 |
2273 if (new_last_in_use != last_in_use) { | 2149 if (new_last_in_use != last_in_use) { |
2274 // Current allocation top points to a page which is now in the middle | 2150 // Current allocation top points to a page which is now in the middle |
2275 // of page list. We should move allocation top forward to the new last | 2151 // of page list. We should move allocation top forward to the new last |
2276 // used page so various object iterators will continue to work properly. | 2152 // used page so various object iterators will continue to work properly. |
2277 int size_in_bytes = static_cast<int>(PageAllocationLimit(last_in_use) - | 2153 int size_in_bytes = static_cast<int>(PageAllocationLimit(last_in_use) - |
2278 last_in_use->AllocationTop()); | 2154 last_in_use->AllocationTop()); |
2279 | 2155 |
2280 last_in_use->SetAllocationWatermark(last_in_use->AllocationTop()); | 2156 last_in_use->SetAllocationWatermark(last_in_use->AllocationTop()); |
2281 if (size_in_bytes > 0) { | 2157 if (size_in_bytes > 0) { |
2282 Address start = last_in_use->AllocationTop(); | 2158 Address start = last_in_use->AllocationTop(); |
2283 if (deallocate_blocks) { | 2159 if (deallocate_blocks) { |
2284 accounting_stats_.AllocateBytes(size_in_bytes); | 2160 accounting_stats_.AllocateBytes(size_in_bytes); |
2285 DeallocateBlock(start, size_in_bytes, add_to_freelist); | 2161 DeallocateBlock(start, size_in_bytes, add_to_freelist); |
2286 } else { | 2162 } else { |
2287 Heap::CreateFillerObjectAt(start, size_in_bytes); | 2163 heap()->CreateFillerObjectAt(start, size_in_bytes); |
2288 } | 2164 } |
2289 } | 2165 } |
2290 | 2166 |
2291 // New last in use page was in the middle of the list before | 2167 // New last in use page was in the middle of the list before |
2292 // sorting so it full. | 2168 // sorting so it full. |
2293 SetTop(new_last_in_use->AllocationTop()); | 2169 SetTop(new_last_in_use->AllocationTop()); |
2294 | 2170 |
2295 ASSERT(AllocationTopPage() == new_last_in_use); | 2171 ASSERT(AllocationTopPage() == new_last_in_use); |
2296 ASSERT(AllocationTopPage()->WasInUseBeforeMC()); | 2172 ASSERT(AllocationTopPage()->WasInUseBeforeMC()); |
2297 } | 2173 } |
2298 | 2174 |
2299 PageIterator pages_in_use_iterator(this, PageIterator::PAGES_IN_USE); | 2175 PageIterator pages_in_use_iterator(this, PageIterator::PAGES_IN_USE); |
2300 while (pages_in_use_iterator.has_next()) { | 2176 while (pages_in_use_iterator.has_next()) { |
2301 Page* p = pages_in_use_iterator.next(); | 2177 Page* p = pages_in_use_iterator.next(); |
2302 if (!p->WasInUseBeforeMC()) { | 2178 if (!p->WasInUseBeforeMC()) { |
2303 // Empty page is in the middle of a sequence of used pages. | 2179 // Empty page is in the middle of a sequence of used pages. |
2304 // Allocate it as a whole and deallocate immediately. | 2180 // Allocate it as a whole and deallocate immediately. |
2305 int size_in_bytes = static_cast<int>(PageAllocationLimit(p) - | 2181 int size_in_bytes = static_cast<int>(PageAllocationLimit(p) - |
2306 p->ObjectAreaStart()); | 2182 p->ObjectAreaStart()); |
2307 | 2183 |
2308 p->SetAllocationWatermark(p->ObjectAreaStart()); | 2184 p->SetAllocationWatermark(p->ObjectAreaStart()); |
2309 Address start = p->ObjectAreaStart(); | 2185 Address start = p->ObjectAreaStart(); |
2310 if (deallocate_blocks) { | 2186 if (deallocate_blocks) { |
2311 accounting_stats_.AllocateBytes(size_in_bytes); | 2187 accounting_stats_.AllocateBytes(size_in_bytes); |
2312 DeallocateBlock(start, size_in_bytes, add_to_freelist); | 2188 DeallocateBlock(start, size_in_bytes, add_to_freelist); |
2313 } else { | 2189 } else { |
2314 Heap::CreateFillerObjectAt(start, size_in_bytes); | 2190 heap()->CreateFillerObjectAt(start, size_in_bytes); |
2315 } | 2191 } |
2316 } | 2192 } |
2317 } | 2193 } |
2318 | 2194 |
2319 page_list_is_chunk_ordered_ = true; | 2195 page_list_is_chunk_ordered_ = true; |
2320 } | 2196 } |
2321 | 2197 |
2322 | 2198 |
2323 void PagedSpace::PrepareForMarkCompact(bool will_compact) { | 2199 void PagedSpace::PrepareForMarkCompact(bool will_compact) { |
2324 if (will_compact) { | 2200 if (will_compact) { |
2325 RelinkPageListInChunkOrder(false); | 2201 RelinkPageListInChunkOrder(false); |
2326 } | 2202 } |
2327 } | 2203 } |
2328 | 2204 |
2329 | 2205 |
2330 bool PagedSpace::ReserveSpace(int bytes) { | 2206 bool PagedSpace::ReserveSpace(int bytes) { |
2331 Address limit = allocation_info_.limit; | 2207 Address limit = allocation_info_.limit; |
2332 Address top = allocation_info_.top; | 2208 Address top = allocation_info_.top; |
2333 if (limit - top >= bytes) return true; | 2209 if (limit - top >= bytes) return true; |
2334 | 2210 |
2335 // There wasn't enough space in the current page. Lets put the rest | 2211 // There wasn't enough space in the current page. Lets put the rest |
2336 // of the page on the free list and start a fresh page. | 2212 // of the page on the free list and start a fresh page. |
2337 PutRestOfCurrentPageOnFreeList(TopPageOf(allocation_info_)); | 2213 PutRestOfCurrentPageOnFreeList(TopPageOf(allocation_info_)); |
2338 | 2214 |
2339 Page* reserved_page = TopPageOf(allocation_info_); | 2215 Page* reserved_page = TopPageOf(allocation_info_); |
2340 int bytes_left_to_reserve = bytes; | 2216 int bytes_left_to_reserve = bytes; |
2341 while (bytes_left_to_reserve > 0) { | 2217 while (bytes_left_to_reserve > 0) { |
2342 if (!reserved_page->next_page()->is_valid()) { | 2218 if (!reserved_page->next_page()->is_valid()) { |
2343 if (Heap::OldGenerationAllocationLimitReached()) return false; | 2219 if (heap()->OldGenerationAllocationLimitReached()) return false; |
2344 Expand(reserved_page); | 2220 Expand(reserved_page); |
2345 } | 2221 } |
2346 bytes_left_to_reserve -= Page::kPageSize; | 2222 bytes_left_to_reserve -= Page::kPageSize; |
2347 reserved_page = reserved_page->next_page(); | 2223 reserved_page = reserved_page->next_page(); |
2348 if (!reserved_page->is_valid()) return false; | 2224 if (!reserved_page->is_valid()) return false; |
2349 } | 2225 } |
2350 ASSERT(TopPageOf(allocation_info_)->next_page()->is_valid()); | 2226 ASSERT(TopPageOf(allocation_info_)->next_page()->is_valid()); |
2351 TopPageOf(allocation_info_)->next_page()->InvalidateWatermark(true); | 2227 TopPageOf(allocation_info_)->next_page()->InvalidateWatermark(true); |
2352 SetAllocationInfo(&allocation_info_, | 2228 SetAllocationInfo(&allocation_info_, |
2353 TopPageOf(allocation_info_)->next_page()); | 2229 TopPageOf(allocation_info_)->next_page()); |
2354 return true; | 2230 return true; |
2355 } | 2231 } |
2356 | 2232 |
2357 | 2233 |
2358 // You have to call this last, since the implementation from PagedSpace | 2234 // You have to call this last, since the implementation from PagedSpace |
2359 // doesn't know that memory was 'promised' to large object space. | 2235 // doesn't know that memory was 'promised' to large object space. |
2360 bool LargeObjectSpace::ReserveSpace(int bytes) { | 2236 bool LargeObjectSpace::ReserveSpace(int bytes) { |
2361 return Heap::OldGenerationSpaceAvailable() >= bytes; | 2237 return heap()->OldGenerationSpaceAvailable() >= bytes; |
2362 } | 2238 } |
2363 | 2239 |
2364 | 2240 |
2365 // Slow case for normal allocation. Try in order: (1) allocate in the next | 2241 // Slow case for normal allocation. Try in order: (1) allocate in the next |
2366 // page in the space, (2) allocate off the space's free list, (3) expand the | 2242 // page in the space, (2) allocate off the space's free list, (3) expand the |
2367 // space, (4) fail. | 2243 // space, (4) fail. |
2368 HeapObject* OldSpace::SlowAllocateRaw(int size_in_bytes) { | 2244 HeapObject* OldSpace::SlowAllocateRaw(int size_in_bytes) { |
2369 // Linear allocation in this space has failed. If there is another page | 2245 // Linear allocation in this space has failed. If there is another page |
2370 // in the space, move to that page and allocate there. This allocation | 2246 // in the space, move to that page and allocate there. This allocation |
2371 // should succeed (size_in_bytes should not be greater than a page's | 2247 // should succeed (size_in_bytes should not be greater than a page's |
2372 // object area size). | 2248 // object area size). |
2373 Page* current_page = TopPageOf(allocation_info_); | 2249 Page* current_page = TopPageOf(allocation_info_); |
2374 if (current_page->next_page()->is_valid()) { | 2250 if (current_page->next_page()->is_valid()) { |
2375 return AllocateInNextPage(current_page, size_in_bytes); | 2251 return AllocateInNextPage(current_page, size_in_bytes); |
2376 } | 2252 } |
2377 | 2253 |
2378 // There is no next page in this space. Try free list allocation unless that | 2254 // There is no next page in this space. Try free list allocation unless that |
2379 // is currently forbidden. | 2255 // is currently forbidden. |
2380 if (!Heap::linear_allocation()) { | 2256 if (!heap()->linear_allocation()) { |
2381 int wasted_bytes; | 2257 int wasted_bytes; |
2382 Object* result; | 2258 Object* result; |
2383 MaybeObject* maybe = free_list_.Allocate(size_in_bytes, &wasted_bytes); | 2259 MaybeObject* maybe = free_list_.Allocate(size_in_bytes, &wasted_bytes); |
2384 accounting_stats_.WasteBytes(wasted_bytes); | 2260 accounting_stats_.WasteBytes(wasted_bytes); |
2385 if (maybe->ToObject(&result)) { | 2261 if (maybe->ToObject(&result)) { |
2386 accounting_stats_.AllocateBytes(size_in_bytes); | 2262 accounting_stats_.AllocateBytes(size_in_bytes); |
2387 | 2263 |
2388 HeapObject* obj = HeapObject::cast(result); | 2264 HeapObject* obj = HeapObject::cast(result); |
2389 Page* p = Page::FromAddress(obj->address()); | 2265 Page* p = Page::FromAddress(obj->address()); |
2390 | 2266 |
2391 if (obj->address() >= p->AllocationWatermark()) { | 2267 if (obj->address() >= p->AllocationWatermark()) { |
2392 // There should be no hole between the allocation watermark | 2268 // There should be no hole between the allocation watermark |
2393 // and allocated object address. | 2269 // and allocated object address. |
2394 // Memory above the allocation watermark was not swept and | 2270 // Memory above the allocation watermark was not swept and |
2395 // might contain garbage pointers to new space. | 2271 // might contain garbage pointers to new space. |
2396 ASSERT(obj->address() == p->AllocationWatermark()); | 2272 ASSERT(obj->address() == p->AllocationWatermark()); |
2397 p->SetAllocationWatermark(obj->address() + size_in_bytes); | 2273 p->SetAllocationWatermark(obj->address() + size_in_bytes); |
2398 } | 2274 } |
2399 | 2275 |
2400 return obj; | 2276 return obj; |
2401 } | 2277 } |
2402 } | 2278 } |
2403 | 2279 |
2404 // Free list allocation failed and there is no next page. Fail if we have | 2280 // Free list allocation failed and there is no next page. Fail if we have |
2405 // hit the old generation size limit that should cause a garbage | 2281 // hit the old generation size limit that should cause a garbage |
2406 // collection. | 2282 // collection. |
2407 if (!Heap::always_allocate() && Heap::OldGenerationAllocationLimitReached()) { | 2283 if (!heap()->always_allocate() && |
| 2284 heap()->OldGenerationAllocationLimitReached()) { |
2408 return NULL; | 2285 return NULL; |
2409 } | 2286 } |
2410 | 2287 |
2411 // Try to expand the space and allocate in the new next page. | 2288 // Try to expand the space and allocate in the new next page. |
2412 ASSERT(!current_page->next_page()->is_valid()); | 2289 ASSERT(!current_page->next_page()->is_valid()); |
2413 if (Expand(current_page)) { | 2290 if (Expand(current_page)) { |
2414 return AllocateInNextPage(current_page, size_in_bytes); | 2291 return AllocateInNextPage(current_page, size_in_bytes); |
2415 } | 2292 } |
2416 | 2293 |
2417 // Finally, fail. | 2294 // Finally, fail. |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2460 | 2337 |
2461 | 2338 |
2462 void OldSpace::DeallocateBlock(Address start, | 2339 void OldSpace::DeallocateBlock(Address start, |
2463 int size_in_bytes, | 2340 int size_in_bytes, |
2464 bool add_to_freelist) { | 2341 bool add_to_freelist) { |
2465 Free(start, size_in_bytes, add_to_freelist); | 2342 Free(start, size_in_bytes, add_to_freelist); |
2466 } | 2343 } |
2467 | 2344 |
2468 | 2345 |
2469 #ifdef DEBUG | 2346 #ifdef DEBUG |
2470 struct CommentStatistic { | |
2471 const char* comment; | |
2472 int size; | |
2473 int count; | |
2474 void Clear() { | |
2475 comment = NULL; | |
2476 size = 0; | |
2477 count = 0; | |
2478 } | |
2479 }; | |
2480 | |
2481 | |
2482 // must be small, since an iteration is used for lookup | |
2483 const int kMaxComments = 64; | |
2484 static CommentStatistic comments_statistics[kMaxComments+1]; | |
2485 | |
2486 | |
2487 void PagedSpace::ReportCodeStatistics() { | 2347 void PagedSpace::ReportCodeStatistics() { |
| 2348 Isolate* isolate = Isolate::Current(); |
| 2349 CommentStatistic* comments_statistics = |
| 2350 isolate->paged_space_comments_statistics(); |
2488 ReportCodeKindStatistics(); | 2351 ReportCodeKindStatistics(); |
2489 PrintF("Code comment statistics (\" [ comment-txt : size/ " | 2352 PrintF("Code comment statistics (\" [ comment-txt : size/ " |
2490 "count (average)\"):\n"); | 2353 "count (average)\"):\n"); |
2491 for (int i = 0; i <= kMaxComments; i++) { | 2354 for (int i = 0; i <= CommentStatistic::kMaxComments; i++) { |
2492 const CommentStatistic& cs = comments_statistics[i]; | 2355 const CommentStatistic& cs = comments_statistics[i]; |
2493 if (cs.size > 0) { | 2356 if (cs.size > 0) { |
2494 PrintF(" %-30s: %10d/%6d (%d)\n", cs.comment, cs.size, cs.count, | 2357 PrintF(" %-30s: %10d/%6d (%d)\n", cs.comment, cs.size, cs.count, |
2495 cs.size/cs.count); | 2358 cs.size/cs.count); |
2496 } | 2359 } |
2497 } | 2360 } |
2498 PrintF("\n"); | 2361 PrintF("\n"); |
2499 } | 2362 } |
2500 | 2363 |
2501 | 2364 |
2502 void PagedSpace::ResetCodeStatistics() { | 2365 void PagedSpace::ResetCodeStatistics() { |
| 2366 Isolate* isolate = Isolate::Current(); |
| 2367 CommentStatistic* comments_statistics = |
| 2368 isolate->paged_space_comments_statistics(); |
2503 ClearCodeKindStatistics(); | 2369 ClearCodeKindStatistics(); |
2504 for (int i = 0; i < kMaxComments; i++) comments_statistics[i].Clear(); | 2370 for (int i = 0; i < CommentStatistic::kMaxComments; i++) { |
2505 comments_statistics[kMaxComments].comment = "Unknown"; | 2371 comments_statistics[i].Clear(); |
2506 comments_statistics[kMaxComments].size = 0; | 2372 } |
2507 comments_statistics[kMaxComments].count = 0; | 2373 comments_statistics[CommentStatistic::kMaxComments].comment = "Unknown"; |
| 2374 comments_statistics[CommentStatistic::kMaxComments].size = 0; |
| 2375 comments_statistics[CommentStatistic::kMaxComments].count = 0; |
2508 } | 2376 } |
2509 | 2377 |
2510 | 2378 |
2511 // Adds comment to 'comment_statistics' table. Performance OK sa long as | 2379 // Adds comment to 'comment_statistics' table. Performance OK as long as |
2512 // 'kMaxComments' is small | 2380 // 'kMaxComments' is small |
2513 static void EnterComment(const char* comment, int delta) { | 2381 static void EnterComment(Isolate* isolate, const char* comment, int delta) { |
| 2382 CommentStatistic* comments_statistics = |
| 2383 isolate->paged_space_comments_statistics(); |
2514 // Do not count empty comments | 2384 // Do not count empty comments |
2515 if (delta <= 0) return; | 2385 if (delta <= 0) return; |
2516 CommentStatistic* cs = &comments_statistics[kMaxComments]; | 2386 CommentStatistic* cs = &comments_statistics[CommentStatistic::kMaxComments]; |
2517 // Search for a free or matching entry in 'comments_statistics': 'cs' | 2387 // Search for a free or matching entry in 'comments_statistics': 'cs' |
2518 // points to result. | 2388 // points to result. |
2519 for (int i = 0; i < kMaxComments; i++) { | 2389 for (int i = 0; i < CommentStatistic::kMaxComments; i++) { |
2520 if (comments_statistics[i].comment == NULL) { | 2390 if (comments_statistics[i].comment == NULL) { |
2521 cs = &comments_statistics[i]; | 2391 cs = &comments_statistics[i]; |
2522 cs->comment = comment; | 2392 cs->comment = comment; |
2523 break; | 2393 break; |
2524 } else if (strcmp(comments_statistics[i].comment, comment) == 0) { | 2394 } else if (strcmp(comments_statistics[i].comment, comment) == 0) { |
2525 cs = &comments_statistics[i]; | 2395 cs = &comments_statistics[i]; |
2526 break; | 2396 break; |
2527 } | 2397 } |
2528 } | 2398 } |
2529 // Update entry for 'comment' | 2399 // Update entry for 'comment' |
2530 cs->size += delta; | 2400 cs->size += delta; |
2531 cs->count += 1; | 2401 cs->count += 1; |
2532 } | 2402 } |
2533 | 2403 |
2534 | 2404 |
2535 // Call for each nested comment start (start marked with '[ xxx', end marked | 2405 // Call for each nested comment start (start marked with '[ xxx', end marked |
2536 // with ']'. RelocIterator 'it' must point to a comment reloc info. | 2406 // with ']'. RelocIterator 'it' must point to a comment reloc info. |
2537 static void CollectCommentStatistics(RelocIterator* it) { | 2407 static void CollectCommentStatistics(Isolate* isolate, RelocIterator* it) { |
2538 ASSERT(!it->done()); | 2408 ASSERT(!it->done()); |
2539 ASSERT(it->rinfo()->rmode() == RelocInfo::COMMENT); | 2409 ASSERT(it->rinfo()->rmode() == RelocInfo::COMMENT); |
2540 const char* tmp = reinterpret_cast<const char*>(it->rinfo()->data()); | 2410 const char* tmp = reinterpret_cast<const char*>(it->rinfo()->data()); |
2541 if (tmp[0] != '[') { | 2411 if (tmp[0] != '[') { |
2542 // Not a nested comment; skip | 2412 // Not a nested comment; skip |
2543 return; | 2413 return; |
2544 } | 2414 } |
2545 | 2415 |
2546 // Search for end of nested comment or a new nested comment | 2416 // Search for end of nested comment or a new nested comment |
2547 const char* const comment_txt = | 2417 const char* const comment_txt = |
2548 reinterpret_cast<const char*>(it->rinfo()->data()); | 2418 reinterpret_cast<const char*>(it->rinfo()->data()); |
2549 const byte* prev_pc = it->rinfo()->pc(); | 2419 const byte* prev_pc = it->rinfo()->pc(); |
2550 int flat_delta = 0; | 2420 int flat_delta = 0; |
2551 it->next(); | 2421 it->next(); |
2552 while (true) { | 2422 while (true) { |
2553 // All nested comments must be terminated properly, and therefore exit | 2423 // All nested comments must be terminated properly, and therefore exit |
2554 // from loop. | 2424 // from loop. |
2555 ASSERT(!it->done()); | 2425 ASSERT(!it->done()); |
2556 if (it->rinfo()->rmode() == RelocInfo::COMMENT) { | 2426 if (it->rinfo()->rmode() == RelocInfo::COMMENT) { |
2557 const char* const txt = | 2427 const char* const txt = |
2558 reinterpret_cast<const char*>(it->rinfo()->data()); | 2428 reinterpret_cast<const char*>(it->rinfo()->data()); |
2559 flat_delta += static_cast<int>(it->rinfo()->pc() - prev_pc); | 2429 flat_delta += static_cast<int>(it->rinfo()->pc() - prev_pc); |
2560 if (txt[0] == ']') break; // End of nested comment | 2430 if (txt[0] == ']') break; // End of nested comment |
2561 // A new comment | 2431 // A new comment |
2562 CollectCommentStatistics(it); | 2432 CollectCommentStatistics(isolate, it); |
2563 // Skip code that was covered with previous comment | 2433 // Skip code that was covered with previous comment |
2564 prev_pc = it->rinfo()->pc(); | 2434 prev_pc = it->rinfo()->pc(); |
2565 } | 2435 } |
2566 it->next(); | 2436 it->next(); |
2567 } | 2437 } |
2568 EnterComment(comment_txt, flat_delta); | 2438 EnterComment(isolate, comment_txt, flat_delta); |
2569 } | 2439 } |
2570 | 2440 |
2571 | 2441 |
2572 // Collects code size statistics: | 2442 // Collects code size statistics: |
2573 // - by code kind | 2443 // - by code kind |
2574 // - by code comment | 2444 // - by code comment |
2575 void PagedSpace::CollectCodeStatistics() { | 2445 void PagedSpace::CollectCodeStatistics() { |
| 2446 Isolate* isolate = heap()->isolate(); |
2576 HeapObjectIterator obj_it(this); | 2447 HeapObjectIterator obj_it(this); |
2577 for (HeapObject* obj = obj_it.next(); obj != NULL; obj = obj_it.next()) { | 2448 for (HeapObject* obj = obj_it.next(); obj != NULL; obj = obj_it.next()) { |
2578 if (obj->IsCode()) { | 2449 if (obj->IsCode()) { |
2579 Code* code = Code::cast(obj); | 2450 Code* code = Code::cast(obj); |
2580 code_kind_statistics[code->kind()] += code->Size(); | 2451 isolate->code_kind_statistics()[code->kind()] += code->Size(); |
2581 RelocIterator it(code); | 2452 RelocIterator it(code); |
2582 int delta = 0; | 2453 int delta = 0; |
2583 const byte* prev_pc = code->instruction_start(); | 2454 const byte* prev_pc = code->instruction_start(); |
2584 while (!it.done()) { | 2455 while (!it.done()) { |
2585 if (it.rinfo()->rmode() == RelocInfo::COMMENT) { | 2456 if (it.rinfo()->rmode() == RelocInfo::COMMENT) { |
2586 delta += static_cast<int>(it.rinfo()->pc() - prev_pc); | 2457 delta += static_cast<int>(it.rinfo()->pc() - prev_pc); |
2587 CollectCommentStatistics(&it); | 2458 CollectCommentStatistics(isolate, &it); |
2588 prev_pc = it.rinfo()->pc(); | 2459 prev_pc = it.rinfo()->pc(); |
2589 } | 2460 } |
2590 it.next(); | 2461 it.next(); |
2591 } | 2462 } |
2592 | 2463 |
2593 ASSERT(code->instruction_start() <= prev_pc && | 2464 ASSERT(code->instruction_start() <= prev_pc && |
2594 prev_pc <= code->instruction_end()); | 2465 prev_pc <= code->instruction_end()); |
2595 delta += static_cast<int>(code->instruction_end() - prev_pc); | 2466 delta += static_cast<int>(code->instruction_end() - prev_pc); |
2596 EnterComment("NoComment", delta); | 2467 EnterComment(isolate, "NoComment", delta); |
2597 } | 2468 } |
2598 } | 2469 } |
2599 } | 2470 } |
2600 | 2471 |
2601 | 2472 |
2602 void OldSpace::ReportStatistics() { | 2473 void OldSpace::ReportStatistics() { |
2603 int pct = static_cast<int>(Available() * 100 / Capacity()); | 2474 int pct = static_cast<int>(Available() * 100 / Capacity()); |
2604 PrintF(" capacity: %" V8_PTR_PREFIX "d" | 2475 PrintF(" capacity: %" V8_PTR_PREFIX "d" |
2605 ", waste: %" V8_PTR_PREFIX "d" | 2476 ", waste: %" V8_PTR_PREFIX "d" |
2606 ", available: %" V8_PTR_PREFIX "d, %%%d\n", | 2477 ", available: %" V8_PTR_PREFIX "d, %%%d\n", |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2680 // in the space, move to that page and allocate there. This allocation | 2551 // in the space, move to that page and allocate there. This allocation |
2681 // should succeed. | 2552 // should succeed. |
2682 Page* current_page = TopPageOf(allocation_info_); | 2553 Page* current_page = TopPageOf(allocation_info_); |
2683 if (current_page->next_page()->is_valid()) { | 2554 if (current_page->next_page()->is_valid()) { |
2684 return AllocateInNextPage(current_page, size_in_bytes); | 2555 return AllocateInNextPage(current_page, size_in_bytes); |
2685 } | 2556 } |
2686 | 2557 |
2687 // There is no next page in this space. Try free list allocation unless | 2558 // There is no next page in this space. Try free list allocation unless |
2688 // that is currently forbidden. The fixed space free list implicitly assumes | 2559 // that is currently forbidden. The fixed space free list implicitly assumes |
2689 // that all free blocks are of the fixed size. | 2560 // that all free blocks are of the fixed size. |
2690 if (!Heap::linear_allocation()) { | 2561 if (!heap()->linear_allocation()) { |
2691 Object* result; | 2562 Object* result; |
2692 MaybeObject* maybe = free_list_.Allocate(); | 2563 MaybeObject* maybe = free_list_.Allocate(); |
2693 if (maybe->ToObject(&result)) { | 2564 if (maybe->ToObject(&result)) { |
2694 accounting_stats_.AllocateBytes(size_in_bytes); | 2565 accounting_stats_.AllocateBytes(size_in_bytes); |
2695 HeapObject* obj = HeapObject::cast(result); | 2566 HeapObject* obj = HeapObject::cast(result); |
2696 Page* p = Page::FromAddress(obj->address()); | 2567 Page* p = Page::FromAddress(obj->address()); |
2697 | 2568 |
2698 if (obj->address() >= p->AllocationWatermark()) { | 2569 if (obj->address() >= p->AllocationWatermark()) { |
2699 // There should be no hole between the allocation watermark | 2570 // There should be no hole between the allocation watermark |
2700 // and allocated object address. | 2571 // and allocated object address. |
2701 // Memory above the allocation watermark was not swept and | 2572 // Memory above the allocation watermark was not swept and |
2702 // might contain garbage pointers to new space. | 2573 // might contain garbage pointers to new space. |
2703 ASSERT(obj->address() == p->AllocationWatermark()); | 2574 ASSERT(obj->address() == p->AllocationWatermark()); |
2704 p->SetAllocationWatermark(obj->address() + size_in_bytes); | 2575 p->SetAllocationWatermark(obj->address() + size_in_bytes); |
2705 } | 2576 } |
2706 | 2577 |
2707 return obj; | 2578 return obj; |
2708 } | 2579 } |
2709 } | 2580 } |
2710 | 2581 |
2711 // Free list allocation failed and there is no next page. Fail if we have | 2582 // Free list allocation failed and there is no next page. Fail if we have |
2712 // hit the old generation size limit that should cause a garbage | 2583 // hit the old generation size limit that should cause a garbage |
2713 // collection. | 2584 // collection. |
2714 if (!Heap::always_allocate() && Heap::OldGenerationAllocationLimitReached()) { | 2585 if (!heap()->always_allocate() && |
| 2586 heap()->OldGenerationAllocationLimitReached()) { |
2715 return NULL; | 2587 return NULL; |
2716 } | 2588 } |
2717 | 2589 |
2718 // Try to expand the space and allocate in the new next page. | 2590 // Try to expand the space and allocate in the new next page. |
2719 ASSERT(!current_page->next_page()->is_valid()); | 2591 ASSERT(!current_page->next_page()->is_valid()); |
2720 if (Expand(current_page)) { | 2592 if (Expand(current_page)) { |
2721 return AllocateInNextPage(current_page, size_in_bytes); | 2593 return AllocateInNextPage(current_page, size_in_bytes); |
2722 } | 2594 } |
2723 | 2595 |
2724 // Finally, fail. | 2596 // Finally, fail. |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2806 #endif | 2678 #endif |
2807 | 2679 |
2808 | 2680 |
2809 // ----------------------------------------------------------------------------- | 2681 // ----------------------------------------------------------------------------- |
2810 // GlobalPropertyCellSpace implementation | 2682 // GlobalPropertyCellSpace implementation |
2811 | 2683 |
2812 #ifdef DEBUG | 2684 #ifdef DEBUG |
2813 void CellSpace::VerifyObject(HeapObject* object) { | 2685 void CellSpace::VerifyObject(HeapObject* object) { |
2814 // The object should be a global object property cell or a free-list node. | 2686 // The object should be a global object property cell or a free-list node. |
2815 ASSERT(object->IsJSGlobalPropertyCell() || | 2687 ASSERT(object->IsJSGlobalPropertyCell() || |
2816 object->map() == Heap::two_pointer_filler_map()); | 2688 object->map() == heap()->two_pointer_filler_map()); |
2817 } | 2689 } |
2818 #endif | 2690 #endif |
2819 | 2691 |
2820 | 2692 |
2821 // ----------------------------------------------------------------------------- | 2693 // ----------------------------------------------------------------------------- |
2822 // LargeObjectIterator | 2694 // LargeObjectIterator |
2823 | 2695 |
2824 LargeObjectIterator::LargeObjectIterator(LargeObjectSpace* space) { | 2696 LargeObjectIterator::LargeObjectIterator(LargeObjectSpace* space) { |
2825 current_ = space->first_chunk_; | 2697 current_ = space->first_chunk_; |
2826 size_func_ = NULL; | 2698 size_func_ = NULL; |
(...skipping 16 matching lines...) Expand all Loading... |
2843 } | 2715 } |
2844 | 2716 |
2845 | 2717 |
2846 // ----------------------------------------------------------------------------- | 2718 // ----------------------------------------------------------------------------- |
2847 // LargeObjectChunk | 2719 // LargeObjectChunk |
2848 | 2720 |
2849 LargeObjectChunk* LargeObjectChunk::New(int size_in_bytes, | 2721 LargeObjectChunk* LargeObjectChunk::New(int size_in_bytes, |
2850 Executability executable) { | 2722 Executability executable) { |
2851 size_t requested = ChunkSizeFor(size_in_bytes); | 2723 size_t requested = ChunkSizeFor(size_in_bytes); |
2852 size_t size; | 2724 size_t size; |
2853 void* mem = MemoryAllocator::AllocateRawMemory(requested, &size, executable); | 2725 Isolate* isolate = Isolate::Current(); |
| 2726 void* mem = isolate->memory_allocator()->AllocateRawMemory( |
| 2727 requested, &size, executable); |
2854 if (mem == NULL) return NULL; | 2728 if (mem == NULL) return NULL; |
2855 | 2729 |
2856 // The start of the chunk may be overlayed with a page so we have to | 2730 // The start of the chunk may be overlayed with a page so we have to |
2857 // make sure that the page flags fit in the size field. | 2731 // make sure that the page flags fit in the size field. |
2858 ASSERT((size & Page::kPageFlagMask) == 0); | 2732 ASSERT((size & Page::kPageFlagMask) == 0); |
2859 | 2733 |
2860 LOG(NewEvent("LargeObjectChunk", mem, size)); | 2734 LOG(isolate, NewEvent("LargeObjectChunk", mem, size)); |
2861 if (size < requested) { | 2735 if (size < requested) { |
2862 MemoryAllocator::FreeRawMemory(mem, size, executable); | 2736 isolate->memory_allocator()->FreeRawMemory( |
2863 LOG(DeleteEvent("LargeObjectChunk", mem)); | 2737 mem, size, executable); |
| 2738 LOG(isolate, DeleteEvent("LargeObjectChunk", mem)); |
2864 return NULL; | 2739 return NULL; |
2865 } | 2740 } |
2866 | 2741 |
2867 ObjectSpace space = (executable == EXECUTABLE) | 2742 ObjectSpace space = (executable == EXECUTABLE) |
2868 ? kObjectSpaceCodeSpace | 2743 ? kObjectSpaceCodeSpace |
2869 : kObjectSpaceLoSpace; | 2744 : kObjectSpaceLoSpace; |
2870 MemoryAllocator::PerformAllocationCallback( | 2745 isolate->memory_allocator()->PerformAllocationCallback( |
2871 space, kAllocationActionAllocate, size); | 2746 space, kAllocationActionAllocate, size); |
2872 | 2747 |
2873 LargeObjectChunk* chunk = reinterpret_cast<LargeObjectChunk*>(mem); | 2748 LargeObjectChunk* chunk = reinterpret_cast<LargeObjectChunk*>(mem); |
2874 chunk->size_ = size; | 2749 chunk->size_ = size; |
| 2750 Page* page = Page::FromAddress(RoundUp(chunk->address(), Page::kPageSize)); |
| 2751 page->heap_ = Isolate::Current()->heap(); |
2875 return chunk; | 2752 return chunk; |
2876 } | 2753 } |
2877 | 2754 |
2878 | 2755 |
2879 int LargeObjectChunk::ChunkSizeFor(int size_in_bytes) { | 2756 int LargeObjectChunk::ChunkSizeFor(int size_in_bytes) { |
2880 int os_alignment = static_cast<int>(OS::AllocateAlignment()); | 2757 int os_alignment = static_cast<int>(OS::AllocateAlignment()); |
2881 if (os_alignment < Page::kPageSize) { | 2758 if (os_alignment < Page::kPageSize) { |
2882 size_in_bytes += (Page::kPageSize - os_alignment); | 2759 size_in_bytes += (Page::kPageSize - os_alignment); |
2883 } | 2760 } |
2884 return size_in_bytes + Page::kObjectStartOffset; | 2761 return size_in_bytes + Page::kObjectStartOffset; |
2885 } | 2762 } |
2886 | 2763 |
2887 // ----------------------------------------------------------------------------- | 2764 // ----------------------------------------------------------------------------- |
2888 // LargeObjectSpace | 2765 // LargeObjectSpace |
2889 | 2766 |
2890 LargeObjectSpace::LargeObjectSpace(AllocationSpace id) | 2767 LargeObjectSpace::LargeObjectSpace(Heap* heap, AllocationSpace id) |
2891 : Space(id, NOT_EXECUTABLE), // Managed on a per-allocation basis | 2768 : Space(heap, id, NOT_EXECUTABLE), // Managed on a per-allocation basis |
2892 first_chunk_(NULL), | 2769 first_chunk_(NULL), |
2893 size_(0), | 2770 size_(0), |
2894 page_count_(0), | 2771 page_count_(0), |
2895 objects_size_(0) {} | 2772 objects_size_(0) {} |
2896 | 2773 |
2897 | 2774 |
2898 bool LargeObjectSpace::Setup() { | 2775 bool LargeObjectSpace::Setup() { |
2899 first_chunk_ = NULL; | 2776 first_chunk_ = NULL; |
2900 size_ = 0; | 2777 size_ = 0; |
2901 page_count_ = 0; | 2778 page_count_ = 0; |
2902 objects_size_ = 0; | 2779 objects_size_ = 0; |
2903 return true; | 2780 return true; |
2904 } | 2781 } |
2905 | 2782 |
2906 | 2783 |
2907 void LargeObjectSpace::TearDown() { | 2784 void LargeObjectSpace::TearDown() { |
2908 while (first_chunk_ != NULL) { | 2785 while (first_chunk_ != NULL) { |
2909 LargeObjectChunk* chunk = first_chunk_; | 2786 LargeObjectChunk* chunk = first_chunk_; |
2910 first_chunk_ = first_chunk_->next(); | 2787 first_chunk_ = first_chunk_->next(); |
2911 LOG(DeleteEvent("LargeObjectChunk", chunk->address())); | 2788 LOG(heap()->isolate(), DeleteEvent("LargeObjectChunk", chunk->address())); |
2912 Page* page = Page::FromAddress(RoundUp(chunk->address(), Page::kPageSize)); | 2789 Page* page = Page::FromAddress(RoundUp(chunk->address(), Page::kPageSize)); |
2913 Executability executable = | 2790 Executability executable = |
2914 page->IsPageExecutable() ? EXECUTABLE : NOT_EXECUTABLE; | 2791 page->IsPageExecutable() ? EXECUTABLE : NOT_EXECUTABLE; |
2915 ObjectSpace space = kObjectSpaceLoSpace; | 2792 ObjectSpace space = kObjectSpaceLoSpace; |
2916 if (executable == EXECUTABLE) space = kObjectSpaceCodeSpace; | 2793 if (executable == EXECUTABLE) space = kObjectSpaceCodeSpace; |
2917 size_t size = chunk->size(); | 2794 size_t size = chunk->size(); |
2918 MemoryAllocator::FreeRawMemory(chunk->address(), size, executable); | 2795 heap()->isolate()->memory_allocator()->FreeRawMemory(chunk->address(), |
2919 MemoryAllocator::PerformAllocationCallback( | 2796 size, |
| 2797 executable); |
| 2798 heap()->isolate()->memory_allocator()->PerformAllocationCallback( |
2920 space, kAllocationActionFree, size); | 2799 space, kAllocationActionFree, size); |
2921 } | 2800 } |
2922 | 2801 |
2923 size_ = 0; | 2802 size_ = 0; |
2924 page_count_ = 0; | 2803 page_count_ = 0; |
2925 objects_size_ = 0; | 2804 objects_size_ = 0; |
2926 } | 2805 } |
2927 | 2806 |
2928 | 2807 |
2929 #ifdef ENABLE_HEAP_PROTECTION | 2808 #ifdef ENABLE_HEAP_PROTECTION |
2930 | 2809 |
2931 void LargeObjectSpace::Protect() { | 2810 void LargeObjectSpace::Protect() { |
2932 LargeObjectChunk* chunk = first_chunk_; | 2811 LargeObjectChunk* chunk = first_chunk_; |
2933 while (chunk != NULL) { | 2812 while (chunk != NULL) { |
2934 MemoryAllocator::Protect(chunk->address(), chunk->size()); | 2813 heap()->isolate()->memory_allocator()->Protect(chunk->address(), |
| 2814 chunk->size()); |
2935 chunk = chunk->next(); | 2815 chunk = chunk->next(); |
2936 } | 2816 } |
2937 } | 2817 } |
2938 | 2818 |
2939 | 2819 |
2940 void LargeObjectSpace::Unprotect() { | 2820 void LargeObjectSpace::Unprotect() { |
2941 LargeObjectChunk* chunk = first_chunk_; | 2821 LargeObjectChunk* chunk = first_chunk_; |
2942 while (chunk != NULL) { | 2822 while (chunk != NULL) { |
2943 bool is_code = chunk->GetObject()->IsCode(); | 2823 bool is_code = chunk->GetObject()->IsCode(); |
2944 MemoryAllocator::Unprotect(chunk->address(), chunk->size(), | 2824 heap()->isolate()->memory_allocator()->Unprotect(chunk->address(), |
2945 is_code ? EXECUTABLE : NOT_EXECUTABLE); | 2825 chunk->size(), is_code ? EXECUTABLE : NOT_EXECUTABLE); |
2946 chunk = chunk->next(); | 2826 chunk = chunk->next(); |
2947 } | 2827 } |
2948 } | 2828 } |
2949 | 2829 |
2950 #endif | 2830 #endif |
2951 | 2831 |
2952 | 2832 |
2953 MaybeObject* LargeObjectSpace::AllocateRawInternal(int requested_size, | 2833 MaybeObject* LargeObjectSpace::AllocateRawInternal(int requested_size, |
2954 int object_size, | 2834 int object_size, |
2955 Executability executable) { | 2835 Executability executable) { |
2956 ASSERT(0 < object_size && object_size <= requested_size); | 2836 ASSERT(0 < object_size && object_size <= requested_size); |
2957 | 2837 |
2958 // Check if we want to force a GC before growing the old space further. | 2838 // Check if we want to force a GC before growing the old space further. |
2959 // If so, fail the allocation. | 2839 // If so, fail the allocation. |
2960 if (!Heap::always_allocate() && Heap::OldGenerationAllocationLimitReached()) { | 2840 if (!heap()->always_allocate() && |
| 2841 heap()->OldGenerationAllocationLimitReached()) { |
2961 return Failure::RetryAfterGC(identity()); | 2842 return Failure::RetryAfterGC(identity()); |
2962 } | 2843 } |
2963 | 2844 |
2964 LargeObjectChunk* chunk = LargeObjectChunk::New(requested_size, executable); | 2845 LargeObjectChunk* chunk = LargeObjectChunk::New(requested_size, executable); |
2965 if (chunk == NULL) { | 2846 if (chunk == NULL) { |
2966 return Failure::RetryAfterGC(identity()); | 2847 return Failure::RetryAfterGC(identity()); |
2967 } | 2848 } |
2968 | 2849 |
2969 size_ += static_cast<int>(chunk->size()); | 2850 size_ += static_cast<int>(chunk->size()); |
2970 objects_size_ += requested_size; | 2851 objects_size_ += requested_size; |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3055 // regions (modulo 32). So we treat a large page as a sequence of | 2936 // regions (modulo 32). So we treat a large page as a sequence of |
3056 // normal pages of size Page::kPageSize having same dirty marks | 2937 // normal pages of size Page::kPageSize having same dirty marks |
3057 // and subsequently iterate dirty regions on each of these pages. | 2938 // and subsequently iterate dirty regions on each of these pages. |
3058 Address start = object->address(); | 2939 Address start = object->address(); |
3059 Address end = page->ObjectAreaEnd(); | 2940 Address end = page->ObjectAreaEnd(); |
3060 Address object_end = start + object->Size(); | 2941 Address object_end = start + object->Size(); |
3061 | 2942 |
3062 // Iterate regions of the first normal page covering object. | 2943 // Iterate regions of the first normal page covering object. |
3063 uint32_t first_region_number = page->GetRegionNumberForAddress(start); | 2944 uint32_t first_region_number = page->GetRegionNumberForAddress(start); |
3064 newmarks |= | 2945 newmarks |= |
3065 Heap::IterateDirtyRegions(marks >> first_region_number, | 2946 heap()->IterateDirtyRegions(marks >> first_region_number, |
3066 start, | 2947 start, |
3067 end, | 2948 end, |
3068 &Heap::IteratePointersInDirtyRegion, | 2949 &Heap::IteratePointersInDirtyRegion, |
3069 copy_object) << first_region_number; | 2950 copy_object) << first_region_number; |
3070 | 2951 |
3071 start = end; | 2952 start = end; |
3072 end = start + Page::kPageSize; | 2953 end = start + Page::kPageSize; |
3073 while (end <= object_end) { | 2954 while (end <= object_end) { |
3074 // Iterate next 32 regions. | 2955 // Iterate next 32 regions. |
3075 newmarks |= | 2956 newmarks |= |
3076 Heap::IterateDirtyRegions(marks, | 2957 heap()->IterateDirtyRegions(marks, |
3077 start, | 2958 start, |
3078 end, | 2959 end, |
3079 &Heap::IteratePointersInDirtyRegion, | 2960 &Heap::IteratePointersInDirtyRegion, |
3080 copy_object); | 2961 copy_object); |
3081 start = end; | 2962 start = end; |
3082 end = start + Page::kPageSize; | 2963 end = start + Page::kPageSize; |
3083 } | 2964 } |
3084 | 2965 |
3085 if (start != object_end) { | 2966 if (start != object_end) { |
3086 // Iterate the last piece of an object which is less than | 2967 // Iterate the last piece of an object which is less than |
3087 // Page::kPageSize. | 2968 // Page::kPageSize. |
3088 newmarks |= | 2969 newmarks |= |
3089 Heap::IterateDirtyRegions(marks, | 2970 heap()->IterateDirtyRegions(marks, |
3090 start, | 2971 start, |
3091 object_end, | 2972 object_end, |
3092 &Heap::IteratePointersInDirtyRegion, | 2973 &Heap::IteratePointersInDirtyRegion, |
3093 copy_object); | 2974 copy_object); |
3094 } | 2975 } |
3095 | 2976 |
3096 page->SetRegionMarks(newmarks); | 2977 page->SetRegionMarks(newmarks); |
3097 } | 2978 } |
3098 } | 2979 } |
3099 } | 2980 } |
3100 } | 2981 } |
3101 | 2982 |
3102 | 2983 |
3103 void LargeObjectSpace::FreeUnmarkedObjects() { | 2984 void LargeObjectSpace::FreeUnmarkedObjects() { |
3104 LargeObjectChunk* previous = NULL; | 2985 LargeObjectChunk* previous = NULL; |
3105 LargeObjectChunk* current = first_chunk_; | 2986 LargeObjectChunk* current = first_chunk_; |
3106 while (current != NULL) { | 2987 while (current != NULL) { |
3107 HeapObject* object = current->GetObject(); | 2988 HeapObject* object = current->GetObject(); |
3108 if (object->IsMarked()) { | 2989 if (object->IsMarked()) { |
3109 object->ClearMark(); | 2990 object->ClearMark(); |
3110 MarkCompactCollector::tracer()->decrement_marked_count(); | 2991 heap()->mark_compact_collector()->tracer()->decrement_marked_count(); |
3111 previous = current; | 2992 previous = current; |
3112 current = current->next(); | 2993 current = current->next(); |
3113 } else { | 2994 } else { |
3114 Page* page = Page::FromAddress(RoundUp(current->address(), | 2995 Page* page = Page::FromAddress(RoundUp(current->address(), |
3115 Page::kPageSize)); | 2996 Page::kPageSize)); |
3116 Executability executable = | 2997 Executability executable = |
3117 page->IsPageExecutable() ? EXECUTABLE : NOT_EXECUTABLE; | 2998 page->IsPageExecutable() ? EXECUTABLE : NOT_EXECUTABLE; |
3118 Address chunk_address = current->address(); | 2999 Address chunk_address = current->address(); |
3119 size_t chunk_size = current->size(); | 3000 size_t chunk_size = current->size(); |
3120 | 3001 |
3121 // Cut the chunk out from the chunk list. | 3002 // Cut the chunk out from the chunk list. |
3122 current = current->next(); | 3003 current = current->next(); |
3123 if (previous == NULL) { | 3004 if (previous == NULL) { |
3124 first_chunk_ = current; | 3005 first_chunk_ = current; |
3125 } else { | 3006 } else { |
3126 previous->set_next(current); | 3007 previous->set_next(current); |
3127 } | 3008 } |
3128 | 3009 |
3129 // Free the chunk. | 3010 // Free the chunk. |
3130 MarkCompactCollector::ReportDeleteIfNeeded(object); | 3011 heap()->mark_compact_collector()->ReportDeleteIfNeeded(object); |
3131 LiveObjectList::ProcessNonLive(object); | 3012 LiveObjectList::ProcessNonLive(object); |
3132 | 3013 |
3133 size_ -= static_cast<int>(chunk_size); | 3014 size_ -= static_cast<int>(chunk_size); |
3134 objects_size_ -= object->Size(); | 3015 objects_size_ -= object->Size(); |
3135 page_count_--; | 3016 page_count_--; |
3136 ObjectSpace space = kObjectSpaceLoSpace; | 3017 ObjectSpace space = kObjectSpaceLoSpace; |
3137 if (executable == EXECUTABLE) space = kObjectSpaceCodeSpace; | 3018 if (executable == EXECUTABLE) space = kObjectSpaceCodeSpace; |
3138 MemoryAllocator::FreeRawMemory(chunk_address, chunk_size, executable); | 3019 heap()->isolate()->memory_allocator()->FreeRawMemory(chunk_address, |
3139 MemoryAllocator::PerformAllocationCallback(space, kAllocationActionFree, | 3020 chunk_size, |
3140 size_); | 3021 executable); |
3141 LOG(DeleteEvent("LargeObjectChunk", chunk_address)); | 3022 heap()->isolate()->memory_allocator()->PerformAllocationCallback( |
| 3023 space, kAllocationActionFree, size_); |
| 3024 LOG(heap()->isolate(), DeleteEvent("LargeObjectChunk", chunk_address)); |
3142 } | 3025 } |
3143 } | 3026 } |
3144 } | 3027 } |
3145 | 3028 |
3146 | 3029 |
3147 bool LargeObjectSpace::Contains(HeapObject* object) { | 3030 bool LargeObjectSpace::Contains(HeapObject* object) { |
3148 Address address = object->address(); | 3031 Address address = object->address(); |
3149 if (Heap::new_space()->Contains(address)) { | 3032 if (heap()->new_space()->Contains(address)) { |
3150 return false; | 3033 return false; |
3151 } | 3034 } |
3152 Page* page = Page::FromAddress(address); | 3035 Page* page = Page::FromAddress(address); |
3153 | 3036 |
3154 SLOW_ASSERT(!page->IsLargeObjectPage() | 3037 SLOW_ASSERT(!page->IsLargeObjectPage() |
3155 || !FindObject(address)->IsFailure()); | 3038 || !FindObject(address)->IsFailure()); |
3156 | 3039 |
3157 return page->IsLargeObjectPage(); | 3040 return page->IsLargeObjectPage(); |
3158 } | 3041 } |
3159 | 3042 |
3160 | 3043 |
3161 #ifdef DEBUG | 3044 #ifdef DEBUG |
3162 // We do not assume that the large object iterator works, because it depends | 3045 // We do not assume that the large object iterator works, because it depends |
3163 // on the invariants we are checking during verification. | 3046 // on the invariants we are checking during verification. |
3164 void LargeObjectSpace::Verify() { | 3047 void LargeObjectSpace::Verify() { |
3165 for (LargeObjectChunk* chunk = first_chunk_; | 3048 for (LargeObjectChunk* chunk = first_chunk_; |
3166 chunk != NULL; | 3049 chunk != NULL; |
3167 chunk = chunk->next()) { | 3050 chunk = chunk->next()) { |
3168 // Each chunk contains an object that starts at the large object page's | 3051 // Each chunk contains an object that starts at the large object page's |
3169 // object area start. | 3052 // object area start. |
3170 HeapObject* object = chunk->GetObject(); | 3053 HeapObject* object = chunk->GetObject(); |
3171 Page* page = Page::FromAddress(object->address()); | 3054 Page* page = Page::FromAddress(object->address()); |
3172 ASSERT(object->address() == page->ObjectAreaStart()); | 3055 ASSERT(object->address() == page->ObjectAreaStart()); |
3173 | 3056 |
3174 // The first word should be a map, and we expect all map pointers to be | 3057 // The first word should be a map, and we expect all map pointers to be |
3175 // in map space. | 3058 // in map space. |
3176 Map* map = object->map(); | 3059 Map* map = object->map(); |
3177 ASSERT(map->IsMap()); | 3060 ASSERT(map->IsMap()); |
3178 ASSERT(Heap::map_space()->Contains(map)); | 3061 ASSERT(heap()->map_space()->Contains(map)); |
3179 | 3062 |
3180 // We have only code, sequential strings, external strings | 3063 // We have only code, sequential strings, external strings |
3181 // (sequential strings that have been morphed into external | 3064 // (sequential strings that have been morphed into external |
3182 // strings), fixed arrays, and byte arrays in large object space. | 3065 // strings), fixed arrays, and byte arrays in large object space. |
3183 ASSERT(object->IsCode() || object->IsSeqString() || | 3066 ASSERT(object->IsCode() || object->IsSeqString() || |
3184 object->IsExternalString() || object->IsFixedArray() || | 3067 object->IsExternalString() || object->IsFixedArray() || |
3185 object->IsByteArray()); | 3068 object->IsByteArray()); |
3186 | 3069 |
3187 // The object itself should look OK. | 3070 // The object itself should look OK. |
3188 object->Verify(); | 3071 object->Verify(); |
3189 | 3072 |
3190 // Byte arrays and strings don't have interior pointers. | 3073 // Byte arrays and strings don't have interior pointers. |
3191 if (object->IsCode()) { | 3074 if (object->IsCode()) { |
3192 VerifyPointersVisitor code_visitor; | 3075 VerifyPointersVisitor code_visitor; |
3193 object->IterateBody(map->instance_type(), | 3076 object->IterateBody(map->instance_type(), |
3194 object->Size(), | 3077 object->Size(), |
3195 &code_visitor); | 3078 &code_visitor); |
3196 } else if (object->IsFixedArray()) { | 3079 } else if (object->IsFixedArray()) { |
3197 // We loop over fixed arrays ourselves, rather then using the visitor, | 3080 // We loop over fixed arrays ourselves, rather then using the visitor, |
3198 // because the visitor doesn't support the start/offset iteration | 3081 // because the visitor doesn't support the start/offset iteration |
3199 // needed for IsRegionDirty. | 3082 // needed for IsRegionDirty. |
3200 FixedArray* array = FixedArray::cast(object); | 3083 FixedArray* array = FixedArray::cast(object); |
3201 for (int j = 0; j < array->length(); j++) { | 3084 for (int j = 0; j < array->length(); j++) { |
3202 Object* element = array->get(j); | 3085 Object* element = array->get(j); |
3203 if (element->IsHeapObject()) { | 3086 if (element->IsHeapObject()) { |
3204 HeapObject* element_object = HeapObject::cast(element); | 3087 HeapObject* element_object = HeapObject::cast(element); |
3205 ASSERT(Heap::Contains(element_object)); | 3088 ASSERT(heap()->Contains(element_object)); |
3206 ASSERT(element_object->map()->IsMap()); | 3089 ASSERT(element_object->map()->IsMap()); |
3207 if (Heap::InNewSpace(element_object)) { | 3090 if (heap()->InNewSpace(element_object)) { |
3208 Address array_addr = object->address(); | 3091 Address array_addr = object->address(); |
3209 Address element_addr = array_addr + FixedArray::kHeaderSize + | 3092 Address element_addr = array_addr + FixedArray::kHeaderSize + |
3210 j * kPointerSize; | 3093 j * kPointerSize; |
3211 | 3094 |
3212 ASSERT(Page::FromAddress(array_addr)->IsRegionDirty(element_addr)); | 3095 ASSERT(Page::FromAddress(array_addr)->IsRegionDirty(element_addr)); |
3213 } | 3096 } |
3214 } | 3097 } |
3215 } | 3098 } |
3216 } | 3099 } |
3217 } | 3100 } |
(...skipping 18 matching lines...) Expand all Loading... |
3236 CollectHistogramInfo(obj); | 3119 CollectHistogramInfo(obj); |
3237 } | 3120 } |
3238 | 3121 |
3239 PrintF(" number of objects %d, " | 3122 PrintF(" number of objects %d, " |
3240 "size of objects %" V8_PTR_PREFIX "d\n", num_objects, objects_size_); | 3123 "size of objects %" V8_PTR_PREFIX "d\n", num_objects, objects_size_); |
3241 if (num_objects > 0) ReportHistogram(false); | 3124 if (num_objects > 0) ReportHistogram(false); |
3242 } | 3125 } |
3243 | 3126 |
3244 | 3127 |
3245 void LargeObjectSpace::CollectCodeStatistics() { | 3128 void LargeObjectSpace::CollectCodeStatistics() { |
| 3129 Isolate* isolate = heap()->isolate(); |
3246 LargeObjectIterator obj_it(this); | 3130 LargeObjectIterator obj_it(this); |
3247 for (HeapObject* obj = obj_it.next(); obj != NULL; obj = obj_it.next()) { | 3131 for (HeapObject* obj = obj_it.next(); obj != NULL; obj = obj_it.next()) { |
3248 if (obj->IsCode()) { | 3132 if (obj->IsCode()) { |
3249 Code* code = Code::cast(obj); | 3133 Code* code = Code::cast(obj); |
3250 code_kind_statistics[code->kind()] += code->Size(); | 3134 isolate->code_kind_statistics()[code->kind()] += code->Size(); |
3251 } | 3135 } |
3252 } | 3136 } |
3253 } | 3137 } |
3254 #endif // DEBUG | 3138 #endif // DEBUG |
3255 | 3139 |
3256 } } // namespace v8::internal | 3140 } } // namespace v8::internal |
OLD | NEW |