Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(530)

Side by Side Diff: src/spaces.h

Issue 6639024: Get rid of distinction between below- and above-watermark in page allocation.... (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/gc/
Patch Set: Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2006-2010 the V8 project authors. All rights reserved. 1 // Copyright 2011 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
11 // with the distribution. 11 // with the distribution.
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
60 // buffer overflow) iterate intergenerational pointers without decoding heap 60 // buffer overflow) iterate intergenerational pointers without decoding heap
61 // object maps so if the page belongs to old pointer space or large object 61 // object maps so if the page belongs to old pointer space or large object
62 // space it is essential to guarantee that the page does not contain any 62 // space it is essential to guarantee that the page does not contain any
63 // garbage pointers to new space: every pointer aligned word which satisfies 63 // garbage pointers to new space: every pointer aligned word which satisfies
64 // the Heap::InNewSpace() predicate must be a pointer to a live heap object in 64 // the Heap::InNewSpace() predicate must be a pointer to a live heap object in
65 // new space. Thus objects in old pointer and large object spaces should have a 65 // new space. Thus objects in old pointer and large object spaces should have a
66 // special layout (e.g. no bare integer fields). This requirement does not 66 // special layout (e.g. no bare integer fields). This requirement does not
67 // apply to map space which is iterated in a special fashion. However we still 67 // apply to map space which is iterated in a special fashion. However we still
68 // require pointer fields of dead maps to be cleaned. 68 // require pointer fields of dead maps to be cleaned.
69 // 69 //
70 // To enable lazy cleaning of old space pages we use a notion of allocation 70 // To enable lazy cleaning of old space pages we can mark chunks of the page
71 // watermark. Every pointer under watermark is considered to be well formed. 71 // as being garbage. Garbage sections are marked with a special map. These
72 // Page allocation watermark is not necessarily equal to page allocation top but 72 // sections are skipped when scanning the page, even if we are otherwise
73 // all alive objects on page should reside under allocation watermark. 73 // scanning without regard for object boundaries. Garbage sections are chained
74 // During scavenge allocation watermark might be bumped and invalid pointers 74 // together to form a free list after a GC. Garbage sections created outside
75 // might appear below it. To avoid following them we store a valid watermark 75 // of GCs by object trunctation etc. may not be in the free list chain. Very
76 // into special field in the page header and set a page WATERMARK_INVALIDATED 76 // small free spaces are ignored, they need only be cleaned of bogus pointers
77 // flag. For details see comments in the Page::SetAllocationWatermark() method 77 // into new space.
78 // body.
79 // 78 //
79 // Each page may have up to one special garbage section. The start of this
80 // section is denoted by the top field in the space. The end of the section
81 // is denoted by the limit field in the space. This special garbage section
82 // is not marked with a byte array map in the data. The point of this section
83 // is to enable linear allocation without having to constantly update the byte
84 // array every time the top field is updated and a new object is created. The
85 // special garbage section is not in the chain of garbage sections.
86 //
87 // Since the top and limit fields are in the space, not the page, only one page
88 // has a special garbage section, and if the top and limit are equal then there
89 // is no special garbage section.
80 90
81 // Some assertion macros used in the debugging mode. 91 // Some assertion macros used in the debugging mode.
82 92
83 #define ASSERT_PAGE_ALIGNED(address) \ 93 #define ASSERT_PAGE_ALIGNED(address) \
84 ASSERT((OffsetFrom(address) & Page::kPageAlignmentMask) == 0) 94 ASSERT((OffsetFrom(address) & Page::kPageAlignmentMask) == 0)
85 95
86 #define ASSERT_OBJECT_ALIGNED(address) \ 96 #define ASSERT_OBJECT_ALIGNED(address) \
87 ASSERT((OffsetFrom(address) & kObjectAlignmentMask) == 0) 97 ASSERT((OffsetFrom(address) & kObjectAlignmentMask) == 0)
88 98
89 #define ASSERT_MAP_ALIGNED(address) \ 99 #define ASSERT_MAP_ALIGNED(address) \
90 ASSERT((OffsetFrom(address) & kMapAlignmentMask) == 0) 100 ASSERT((OffsetFrom(address) & kMapAlignmentMask) == 0)
91 101
92 #define ASSERT_OBJECT_SIZE(size) \ 102 #define ASSERT_OBJECT_SIZE(size) \
93 ASSERT((0 < size) && (size <= Page::kMaxHeapObjectSize)) 103 ASSERT((0 < size) && (size <= Page::kMaxHeapObjectSize))
94 104
95 #define ASSERT_PAGE_OFFSET(offset) \ 105 #define ASSERT_PAGE_OFFSET(offset) \
96 ASSERT((Page::kObjectStartOffset <= offset) \ 106 ASSERT((Page::kObjectStartOffset <= offset) \
97 && (offset <= Page::kPageSize)) 107 && (offset <= Page::kPageSize))
98 108
99 #define ASSERT_MAP_PAGE_INDEX(index) \ 109 #define ASSERT_MAP_PAGE_INDEX(index) \
100 ASSERT((0 <= index) && (index <= MapSpace::kMaxMapPageIndex)) 110 ASSERT((0 <= index) && (index <= MapSpace::kMaxMapPageIndex))
101 111
102 112
103 class PagedSpace; 113 class PagedSpace;
104 class MemoryAllocator; 114 class MemoryAllocator;
105 class AllocationInfo; 115 class AllocationInfo;
106 class Space; 116 class Space;
117 class OldSpaceFreeList;
107 118
108 119
109 // Bitmap is a sequence of cells each containing fixed number of bits. 120 // Bitmap is a sequence of cells each containing fixed number of bits.
110 template<typename StorageDescriptor> 121 template<typename StorageDescriptor>
111 class Bitmap { 122 class Bitmap {
112 public: 123 public:
113 typedef uint32_t CellType; 124 typedef uint32_t CellType;
114 static const uint32_t kBitsPerCell = 32; 125 static const uint32_t kBitsPerCell = 32;
115 static const uint32_t kBitsPerCellLog2 = 5; 126 static const uint32_t kBitsPerCellLog2 = 5;
116 static const uint32_t kBitIndexMask = kBitsPerCell - 1; 127 static const uint32_t kBitIndexMask = kBitsPerCell - 1;
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after
289 public: 300 public:
290 static MemoryChunk* FromAddress(Address a) { 301 static MemoryChunk* FromAddress(Address a) {
291 return reinterpret_cast<MemoryChunk*>(OffsetFrom(a) & ~kAlignmentMask); 302 return reinterpret_cast<MemoryChunk*>(OffsetFrom(a) & ~kAlignmentMask);
292 } 303 }
293 304
294 Address address() { return reinterpret_cast<Address>(this); } 305 Address address() { return reinterpret_cast<Address>(this); }
295 306
296 bool is_valid() { return address() != NULL; } 307 bool is_valid() { return address() != NULL; }
297 308
298 MemoryChunk* next_chunk() const { return next_chunk_; } 309 MemoryChunk* next_chunk() const { return next_chunk_; }
310 MemoryChunk* prev_chunk() const { return prev_chunk_; }
299 311
300 void set_next_chunk(MemoryChunk* next) { next_chunk_ = next; } 312 void set_next_chunk(MemoryChunk* next) { next_chunk_ = next; }
313 void set_prev_chunk(MemoryChunk* prev) { prev_chunk_ = prev; }
301 314
302 Space* owner() const { return owner_; } 315 Space* owner() const { return owner_; }
303 316
304 Address body() { return address() + kBodyOffset; } 317 Address body() { return address() + kObjectStartOffset; }
305 318
306 int body_size() { return size() - kBodyOffset; } 319 int body_size() { return size() - kObjectStartOffset; }
307 320
308 enum MemoryChunkFlags { 321 enum MemoryChunkFlags {
309 IS_EXECUTABLE, 322 IS_EXECUTABLE,
323 WAS_SWEPT_CONSERVATIVELY,
310 NUM_MEMORY_CHUNK_FLAGS 324 NUM_MEMORY_CHUNK_FLAGS
311 }; 325 };
312 326
313 void SetFlag(int flag) { 327 void SetFlag(int flag) {
314 flags_ |= 1 << flag; 328 flags_ |= 1 << flag;
315 } 329 }
316 330
317 void ClearFlag(int flag) { 331 void ClearFlag(int flag) {
318 flags_ &= ~(1 << flag); 332 flags_ &= ~(1 << flag);
319 } 333 }
(...skipping 11 matching lines...) Expand all
331 345
332 static const size_t kMarksBitmapLength = 346 static const size_t kMarksBitmapLength =
333 (1 << kPageSizeBits) >> (kPointerSizeLog2); 347 (1 << kPageSizeBits) >> (kPointerSizeLog2);
334 348
335 static const size_t kMarksBitmapSize = 349 static const size_t kMarksBitmapSize =
336 (1 << kPageSizeBits) >> (kPointerSizeLog2 + kBitsPerByteLog2); 350 (1 << kPageSizeBits) >> (kPointerSizeLog2 + kBitsPerByteLog2);
337 351
338 static const int kBodyOffset = 352 static const int kBodyOffset =
339 CODE_POINTER_ALIGN(MAP_POINTER_ALIGN(kHeaderSize + kMarksBitmapSize)); 353 CODE_POINTER_ALIGN(MAP_POINTER_ALIGN(kHeaderSize + kMarksBitmapSize));
340 354
355 // The start offset of the object area in a page. Aligned to both maps and
356 // code alignment to be suitable for both. Also aligned to 32 words because
357 // the marking bitmap is arranged in 32 bit chunks.
358 static const int kObjectStartAlignment = 32 * kPointerSize;
Vyacheslav Egorov (Chromium) 2011/03/15 09:20:09 Why did not you just modify body offset?
Erik Corry 2011/03/17 13:39:17 kObjectStartOffset already existed. I just change
359 static const int kObjectStartOffset = kBodyOffset - 1 +
360 (kObjectStartAlignment - (kBodyOffset - 1) % kObjectStartAlignment);
361
341 size_t size() const { return size_; } 362 size_t size() const { return size_; }
342 363
343 Executability executable() { 364 Executability executable() {
344 return IsFlagSet(IS_EXECUTABLE) ? EXECUTABLE : NOT_EXECUTABLE; 365 return IsFlagSet(IS_EXECUTABLE) ? EXECUTABLE : NOT_EXECUTABLE;
345 } 366 }
346 367
347 // --------------------------------------------------------------------- 368 // ---------------------------------------------------------------------
348 // Markbits support 369 // Markbits support
349 370
350 class BitmapStorageDescriptor { 371 class BitmapStorageDescriptor {
(...skipping 20 matching lines...) Expand all
371 const intptr_t offset = 392 const intptr_t offset =
372 reinterpret_cast<intptr_t>(addr) & kAlignmentMask; 393 reinterpret_cast<intptr_t>(addr) & kAlignmentMask;
373 394
374 return static_cast<uint32_t>(offset) >> kPointerSizeLog2; 395 return static_cast<uint32_t>(offset) >> kPointerSizeLog2;
375 } 396 }
376 397
377 inline Address MarkbitIndexToAddress(uint32_t index) { 398 inline Address MarkbitIndexToAddress(uint32_t index) {
378 return this->address() + (index << kPointerSizeLog2); 399 return this->address() + (index << kPointerSizeLog2);
379 } 400 }
380 401
402 void InsertAfter(MemoryChunk* other);
403 void Unlink();
404
381 protected: 405 protected:
382 MemoryChunk* next_chunk_; 406 MemoryChunk* next_chunk_;
407 MemoryChunk* prev_chunk_;
383 size_t size_; 408 size_t size_;
384 intptr_t flags_; 409 intptr_t flags_;
385 Space* owner_; 410 Space* owner_;
386 411
387 private:
388 static MemoryChunk* Initialize(Address base, 412 static MemoryChunk* Initialize(Address base,
389 size_t size, 413 size_t size,
390 Executability executable, 414 Executability executable,
391 Space* owner) { 415 Space* owner) {
392 MemoryChunk* chunk = FromAddress(base); 416 MemoryChunk* chunk = FromAddress(base);
393 417
394 ASSERT(base == chunk->address()); 418 ASSERT(base == chunk->address());
395 419
396 chunk->next_chunk_ = NULL;
397 chunk->size_ = size; 420 chunk->size_ = size;
398 chunk->flags_ = 0; 421 chunk->flags_ = 0;
399 chunk->owner_ = owner; 422 chunk->owner_ = owner;
400 chunk->markbits()->Clear(); 423 chunk->markbits()->Clear();
401 424
402 if (executable == EXECUTABLE) chunk->SetFlag(IS_EXECUTABLE); 425 if (executable == EXECUTABLE) chunk->SetFlag(IS_EXECUTABLE);
403 426
404 return chunk; 427 return chunk;
405 } 428 }
406 429
430 private:
Vyacheslav Egorov (Chromium) 2011/03/15 09:20:09 does not make much sense to me to have a private s
Erik Corry 2011/03/17 13:39:17 Done.
407 friend class MemoryAllocator; 431 friend class MemoryAllocator;
408 }; 432 };
409 433
410 STATIC_CHECK(sizeof(MemoryChunk) <= MemoryChunk::kHeaderSize); 434 STATIC_CHECK(sizeof(MemoryChunk) <= MemoryChunk::kHeaderSize);
411 435
412 // ----------------------------------------------------------------------------- 436 // -----------------------------------------------------------------------------
413 // A page is a memory chunk of a size 1MB. Large object pages may be larger. 437 // A page is a memory chunk of a size 1MB. Large object pages may be larger.
414 // 438 //
415 // The only way to get a page pointer is by calling factory methods: 439 // The only way to get a page pointer is by calling factory methods:
416 // Page* p = Page::FromAddress(addr); or 440 // Page* p = Page::FromAddress(addr); or
417 // Page* p = Page::FromAllocationTop(top); 441 // Page* p = Page::FromAllocationTop(top);
418 class Page : public MemoryChunk { 442 class Page : public MemoryChunk {
419 public: 443 public:
420 // Returns the page containing a given address. The address ranges 444 // Returns the page containing a given address. The address ranges
421 // from [page_addr .. page_addr + kPageSize[ 445 // from [page_addr .. page_addr + kPageSize[
422 // 446 //
423 // Note that this function only works for addresses in normal paged 447 // Note that this function only works for addresses in normal paged
424 // spaces and addresses in the first 8K of large object pages (i.e., 448 // spaces and addresses in the first 1Mbyte of large object pages (i.e.,
425 // the start of large objects but not necessarily derived pointers 449 // the start of large objects but not necessarily derived pointers
426 // within them). 450 // within them).
427 INLINE(static Page* FromAddress(Address a)) { 451 INLINE(static Page* FromAddress(Address a)) {
428 return reinterpret_cast<Page*>(OffsetFrom(a) & ~kPageAlignmentMask); 452 return reinterpret_cast<Page*>(OffsetFrom(a) & ~kPageAlignmentMask);
429 } 453 }
430 454
431 // Returns the page containing an allocation top. Because an allocation 455 // Returns the page containing an allocation top. Because an allocation
432 // top address can be the upper bound of the page, we need to subtract 456 // top address can be the upper bound of the page, we need to subtract
433 // it with kPointerSize first. The address ranges from 457 // it with kPointerSize first. The address ranges from
434 // [page_addr + kObjectStartOffset .. page_addr + kPageSize]. 458 // [page_addr + kObjectStartOffset .. page_addr + kPageSize].
435 INLINE(static Page* FromAllocationTop(Address top)) { 459 INLINE(static Page* FromAllocationTop(Address top)) {
436 Page* p = FromAddress(top - kPointerSize); 460 Page* p = FromAddress(top - kPointerSize);
437 ASSERT_PAGE_OFFSET(p->Offset(top)); 461 ASSERT_PAGE_OFFSET(p->Offset(top));
438 return p; 462 return p;
439 } 463 }
440 464
441 // Returns the next page in the chain of pages owned by a space. 465 // Returns the next page in the chain of pages owned by a space.
442 inline Page* next_page() { 466 inline Page* next_page();
443 ASSERT(!next_chunk()->is_valid() || next_chunk()->owner() == owner()); 467 inline Page* prev_page();
444 return static_cast<Page*>(next_chunk()); 468 inline void set_next_page(Page* page);
445 } 469 inline void set_prev_page(Page* page);
446 470
447 inline void set_next_page(Page* page) { 471 PagedSpace* owner() const { return reinterpret_cast<PagedSpace*>(owner_); }
448 ASSERT(!page->is_valid() || page->owner() == owner());
449 set_next_chunk(page);
450 }
451
452 // Return the end of allocation in this page. Undefined for unused pages.
453 inline Address AllocationTop();
454
455 // Return the allocation watermark for the page.
456 // For old space pages it is guaranteed that the area under the watermark
457 // does not contain any garbage pointers to new space.
458 inline Address AllocationWatermark();
459
460 // Return the allocation watermark offset from the beginning of the page.
461 inline uint32_t AllocationWatermarkOffset();
462
463 inline void SetAllocationWatermark(Address allocation_watermark);
464
465 inline void SetCachedAllocationWatermark(Address allocation_watermark);
466 inline Address CachedAllocationWatermark();
467 472
468 // Returns the start address of the object area in this page. 473 // Returns the start address of the object area in this page.
469 Address ObjectAreaStart() { return address() + kObjectStartOffset; } 474 Address ObjectAreaStart() { return address() + kObjectStartOffset; }
470 475
471 // Returns the end address (exclusive) of the object area in this page. 476 // Returns the end address (exclusive) of the object area in this page.
472 Address ObjectAreaEnd() { return address() + Page::kPageSize; } 477 Address ObjectAreaEnd() { return address() + Page::kPageSize; }
473 478
474 // Checks whether an address is page aligned. 479 // Checks whether an address is page aligned.
475 static bool IsAlignedToPageSize(Address a) { 480 static bool IsAlignedToPageSize(Address a) {
476 return 0 == (OffsetFrom(a) & kPageAlignmentMask); 481 return 0 == (OffsetFrom(a) & kPageAlignmentMask);
(...skipping 13 matching lines...) Expand all
490 } 495 }
491 496
492 // --------------------------------------------------------------------- 497 // ---------------------------------------------------------------------
493 498
494 // Page size in bytes. This must be a multiple of the OS page size. 499 // Page size in bytes. This must be a multiple of the OS page size.
495 static const int kPageSize = 1 << kPageSizeBits; 500 static const int kPageSize = 1 << kPageSizeBits;
496 501
497 // Page size mask. 502 // Page size mask.
498 static const intptr_t kPageAlignmentMask = (1 << kPageSizeBits) - 1; 503 static const intptr_t kPageAlignmentMask = (1 << kPageSizeBits) - 1;
499 504
500 // The start offset of the object area in a page. Aligned to both maps and
501 // code alignment to be suitable for both.
502 static const int kObjectStartOffset = kBodyOffset;
503
504 // Object area size in bytes. 505 // Object area size in bytes.
505 static const int kObjectAreaSize = kPageSize - kObjectStartOffset; 506 static const int kObjectAreaSize = kPageSize - kObjectStartOffset;
506 507
507 // Maximum object size that fits in a page. 508 // Maximum object size that fits in a page.
508 static const int kMaxHeapObjectSize = kObjectAreaSize; 509 static const int kMaxHeapObjectSize = kObjectAreaSize;
509 510
510 static const int kFirstUsedCell = 511 static const int kFirstUsedCell =
511 (kBodyOffset/kPointerSize) >> MarkbitsBitmap::kBitsPerCellLog2; 512 (kObjectStartOffset/kPointerSize) >> MarkbitsBitmap::kBitsPerCellLog2;
512 513
513 static const int kLastUsedCell = 514 static const int kLastUsedCell =
514 ((kPageSize - kPointerSize)/kPointerSize) >> 515 ((kPageSize - kPointerSize)/kPointerSize) >>
515 MarkbitsBitmap::kBitsPerCellLog2; 516 MarkbitsBitmap::kBitsPerCellLog2;
516 517
517
518 enum PageFlag {
519 // Page allocation watermark was bumped by preallocation during scavenge.
520 // Correct watermark can be retrieved by CachedAllocationWatermark() method
521 WATERMARK_INVALIDATED = NUM_MEMORY_CHUNK_FLAGS,
522
523 // We say that memory region [start_addr, end_addr[ is continuous if
524 // and only if:
525 // a) start_addr coincides with the start of a valid heap object
526 // b) for any valid heap object o in this region address
527 // o->address() + o->Size() is either equal to end_addr or coincides
528 // with the start of a valid heap object.
529 // We say that a page is continuous if and only if the region
530 // [page->ObjectAreaStart(), page->AllocationTop()[ is continuous.
531 // For non-continuous pages we say that address lb is a linearity boundary
532 // if and only if [lb, page->AllocationTop()[ is either empty or continuous.
533 IS_CONTINUOUS,
534
535 NUM_PAGE_FLAGS // Must be last
536 };
537
538 // To avoid an additional WATERMARK_INVALIDATED flag clearing pass during
539 // scavenge we just invalidate the watermark on each old space page after
540 // processing it. And then we flip the meaning of the WATERMARK_INVALIDATED
541 // flag at the beginning of the next scavenge and each page becomes marked as
542 // having a valid watermark.
543 //
544 // The following invariant must hold for pages in old pointer and map spaces:
545 // If page is in use then page is marked as having invalid watermark at
546 // the beginning and at the end of any GC.
547 //
548 // This invariant guarantees that after flipping flag meaning at the
549 // beginning of scavenge all pages in use will be marked as having valid
550 // watermark.
551 static inline void FlipMeaningOfInvalidatedWatermarkFlag();
552
553 // Returns true if the page allocation watermark was not altered during
554 // scavenge.
555 inline bool IsWatermarkValid();
556
557 inline void InvalidateWatermark(bool value);
558
559 inline void ClearGCFields(); 518 inline void ClearGCFields();
560 519
561 static const int kAllocationWatermarkOffsetShift = NUM_PAGE_FLAGS; 520 static inline Page* Initialize(MemoryChunk* chunk,
562 static const int kAllocationWatermarkOffsetBits = kPageSizeBits + 1; 521 Executability executable,
563 static const uint32_t kAllocationWatermarkOffsetMask = 522 PagedSpace* owner);
564 ((1 << kAllocationWatermarkOffsetBits) - 1) <<
565 kAllocationWatermarkOffsetShift;
566 523
567 static const uint32_t kFlagsMask = 524 void InitializeAsAnchor(PagedSpace* owner);
568 ((1 << kAllocationWatermarkOffsetShift) - 1);
569
570 STATIC_CHECK(kBitsPerInt - kAllocationWatermarkOffsetShift >=
571 kAllocationWatermarkOffsetBits);
572
573 // This field contains the meaning of the WATERMARK_INVALIDATED flag.
574 // Instead of clearing this flag from all pages we just flip
575 // its meaning at the beginning of a scavenge.
576 static intptr_t watermark_invalidated_mark_;
577
578 // See comments for IS_CONTINUOUS flag.
579 Address linearity_boundary() { return linearity_boundary_; }
580 void set_linearity_boundary(Address linearity_boundary) {
581 linearity_boundary_ = linearity_boundary;
582 }
583 525
584 private: 526 private:
585 static Page* Initialize(MemoryChunk* chunk) {
586 Page* page = static_cast<Page*>(chunk);
587 page->allocation_watermark_ = page->body();
588 page->InvalidateWatermark(true);
589 page->SetFlag(IS_CONTINUOUS);
590 return page;
591 }
592
593 Address allocation_watermark_;
594
595 // See comments for IS_CONTINUOUS flag.
596 Address linearity_boundary_;
597
598 friend class MemoryAllocator; 527 friend class MemoryAllocator;
599 }; 528 };
600 529
530
601 STATIC_CHECK(sizeof(Page) <= MemoryChunk::kHeaderSize); 531 STATIC_CHECK(sizeof(Page) <= MemoryChunk::kHeaderSize);
602 532
533
603 class LargePage : public MemoryChunk { 534 class LargePage : public MemoryChunk {
604 public: 535 public:
605 HeapObject* GetObject() { 536 HeapObject* GetObject() {
606 return HeapObject::FromAddress(body()); 537 return HeapObject::FromAddress(body());
607 } 538 }
608 539
609 inline LargePage* next_page() const { 540 inline LargePage* next_page() const {
610 return static_cast<LargePage*>(next_chunk()); 541 return static_cast<LargePage*>(next_chunk());
611 } 542 }
612 543
(...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after
897 virtual ~ObjectIterator() { } 828 virtual ~ObjectIterator() { }
898 829
899 virtual HeapObject* next_object() = 0; 830 virtual HeapObject* next_object() = 0;
900 }; 831 };
901 832
902 833
903 // ----------------------------------------------------------------------------- 834 // -----------------------------------------------------------------------------
904 // Heap object iterator in new/old/map spaces. 835 // Heap object iterator in new/old/map spaces.
905 // 836 //
906 // A HeapObjectIterator iterates objects from the bottom of the given space 837 // A HeapObjectIterator iterates objects from the bottom of the given space
907 // to it's top or from the bottom of the given page to it's top. 838 // to its top or from the bottom of the given page to its top.
908 // 839 //
909 // There are some caveats. 840 // If objects are allocated in the page during iteration the iterator may
841 // or may not iterate over those objects. The caller must create a new
842 // iterator starting from the old top in order to be sure to visit these new
843 // objects.
Vyacheslav Egorov (Chromium) 2011/03/15 09:20:09 what if we allocate inside page in the hole? how s
Erik Corry 2011/03/17 13:39:17 Comment clarified.
910 // 844 //
911 // (1) If the space top changes upward during iteration (because of
912 // allocating new objects), the iterator does not iterate objects
913 // above the original space top. The caller must create a new
914 // iterator starting from the old top in order to visit these new
915 // objects.
916 //
917 // (2) If new objects are allocated below the original allocation top
918 // (e.g., free-list allocation in paged spaces), the new objects
919 // may or may not be iterated depending on their position with
920 // respect to the current point of iteration.
921 //
922 // (3) The space top should not change downward during iteration,
923 // otherwise the iterator will return not-necessarily-valid
924 // objects.
925 845
926 class HeapObjectIterator: public ObjectIterator { 846 class HeapObjectIterator: public ObjectIterator {
927 public: 847 public:
928 // Creates a new object iterator in a given space. 848 // Creates a new object iterator in a given space.
929 // If the size function is not given, the iterator calls the default 849 // If the size function is not given, the iterator calls the default
930 // Object::Size(). 850 // Object::Size().
931 explicit HeapObjectIterator(PagedSpace* space); 851 explicit HeapObjectIterator(PagedSpace* space);
932 HeapObjectIterator(PagedSpace* space, HeapObjectCallback size_func); 852 HeapObjectIterator(PagedSpace* space, HeapObjectCallback size_func);
933 HeapObjectIterator(Page* page, HeapObjectCallback size_func); 853 HeapObjectIterator(Page* page, HeapObjectCallback size_func);
934 854
935 inline HeapObject* next() { 855 // Advance to the next object, skipping byte arrays and other fillers and
936 return (cur_addr_ < cur_limit_) ? FromCurrentPage() : FromNextPage(); 856 // skipping the special garbage section of which there is one per space.
857 // Returns NULL when the iteration has ended.
858 inline HeapObject* Next() {
Vyacheslav Egorov (Chromium) 2011/03/15 09:20:09 What if bytearray is really something important wh
Erik Corry 2011/03/17 13:39:17 I have created FreeSpace, which is used where the
859 do {
860 HeapObject* next_obj = FromCurrentPage();
861 if (next_obj != NULL) return next_obj;
862 } while (AdvanceToNextPage());
863 return NULL;
937 } 864 }
938 865
939 // implementation of ObjectIterator. 866 virtual HeapObject* next_object() {
940 virtual HeapObject* next_object() { return next(); } 867 return Next();
868 }
941 869
942 private: 870 private:
943 Address cur_addr_; // current iteration point 871 enum PageMode { kOnePageOnly, kAllPagesInSpace };
944 Address end_addr_; // end iteration point
945 Address cur_limit_; // current page limit
946 HeapObjectCallback size_func_; // size function
947 Page* end_page_; // caches the page of the end address
948 872
949 HeapObject* FromCurrentPage() { 873 Address cur_addr_; // Current iteration point.
950 ASSERT(cur_addr_ < cur_limit_); 874 Address cur_end_; // End iteration point.
951 HeapObject* obj = HeapObject::FromAddress(cur_addr_); 875 HeapObjectCallback size_func_; // Size function or NULL.
876 PagedSpace* space_;
877 PageMode page_mode_;
952 878
953 Page* p = Page::FromAddress(cur_addr_); 879 // Fast (inlined) path of next().
954 if (p->IsFlagSet(Page::IS_CONTINUOUS)) { 880 inline HeapObject* FromCurrentPage();
955 int obj_size = (size_func_ == NULL) ? obj->Size() : size_func_(obj);
956 ASSERT_OBJECT_SIZE(obj_size);
957 881
958 cur_addr_ += obj_size; 882 // Slow path of next(), goes into the next page. Returns false if the
959 ASSERT(cur_addr_ <= cur_limit_); 883 // iteration has ended.
960 } else { 884 bool AdvanceToNextPage();
961 AdvanceUsingMarkbits();
962 }
963
964 return obj;
965 }
966
967 void AdvanceUsingMarkbits();
968
969 // Slow path of next, goes into the next page.
970 HeapObject* FromNextPage();
971 885
972 // Initializes fields. 886 // Initializes fields.
973 void Initialize(Address start, Address end, HeapObjectCallback size_func); 887 inline void Initialize(PagedSpace* owner,
888 Address start,
889 Address end,
890 PageMode mode,
891 HeapObjectCallback size_func);
974 892
975 #ifdef DEBUG 893 #ifdef DEBUG
976 // Verifies whether fields have valid values. 894 // Verifies whether fields have valid values.
977 void Verify(); 895 void Verify();
978 #endif 896 #endif
979 }; 897 };
980 898
981 899
982 // ----------------------------------------------------------------------------- 900 // -----------------------------------------------------------------------------
983 // A PageIterator iterates the pages in a paged space. 901 // A PageIterator iterates the pages in a paged space.
984 //
985 // The PageIterator class provides three modes for iterating pages in a space:
986 // PAGES_IN_USE iterates pages containing allocated objects.
987 // PAGES_USED_BY_MC iterates pages that hold relocated objects during a
988 // mark-compact collection.
989 // ALL_PAGES iterates all pages in the space.
990 //
991 // There are some caveats.
992 //
993 // (1) If the space expands during iteration, new pages will not be
994 // returned by the iterator in any mode.
995 //
996 // (2) If new objects are allocated during iteration, they will appear
997 // in pages returned by the iterator. Allocation may cause the
998 // allocation pointer or MC allocation pointer in the last page to
999 // change between constructing the iterator and iterating the last
1000 // page.
1001 //
1002 // (3) The space should not shrink during iteration, otherwise the
1003 // iterator will return deallocated pages.
1004 902
1005 class PageIterator BASE_EMBEDDED { 903 class PageIterator BASE_EMBEDDED {
1006 public: 904 public:
1007 enum Mode { 905 explicit inline PageIterator(PagedSpace* space);
1008 PAGES_IN_USE,
1009 ALL_PAGES
1010 };
1011
1012 PageIterator(PagedSpace* space, Mode mode);
1013 906
1014 inline bool has_next(); 907 inline bool has_next();
1015 inline Page* next(); 908 inline Page* next();
1016 909
1017 private: 910 private:
1018 PagedSpace* space_; 911 PagedSpace* space_;
1019 Page* prev_page_; // Previous page returned. 912 Page* prev_page_; // Previous page returned.
1020 Page* stop_page_; // Page to stop at (last page returned by the iterator). 913 // Next page that will be returned. Cached here so that we can use this
914 // iterator for operations that deallocate pages.
915 Page* next_page_;
1021 }; 916 };
1022 917
1023 918
1024 // ----------------------------------------------------------------------------- 919 // -----------------------------------------------------------------------------
1025 // A space has a list of pages. The next page can be accessed via 920 // A space has a circular list of pages. The next page can be accessed via
1026 // Page::next_page() call. The next page of the last page is an 921 // Page::next_page() call.
1027 // invalid page pointer. A space can expand and shrink dynamically.
1028 922
1029 // An abstraction of allocation and relocation pointers in a page-structured 923 // An abstraction of allocation and relocation pointers in a page-structured
1030 // space. 924 // space.
1031 class AllocationInfo { 925 class AllocationInfo {
1032 public: 926 public:
1033 Address top; // current allocation top 927 Address top; // Current allocation top.
1034 Address limit; // current allocation limit 928 Address limit; // Current allocation limit.
1035 929
1036 #ifdef DEBUG 930 #ifdef DEBUG
1037 bool VerifyPagedAllocation() { 931 bool VerifyPagedAllocation() {
1038 return (Page::FromAllocationTop(top) == Page::FromAllocationTop(limit)) 932 return (Page::FromAllocationTop(top) == Page::FromAllocationTop(limit))
1039 && (top <= limit); 933 && (top <= limit);
1040 } 934 }
1041 #endif 935 #endif
1042 }; 936 };
1043 937
1044 938
(...skipping 11 matching lines...) Expand all
1056 // functions increase or decrease one of the non-capacity stats in 950 // functions increase or decrease one of the non-capacity stats in
1057 // conjunction with capacity, or else they always balance increases and 951 // conjunction with capacity, or else they always balance increases and
1058 // decreases to the non-capacity stats. 952 // decreases to the non-capacity stats.
1059 class AllocationStats BASE_EMBEDDED { 953 class AllocationStats BASE_EMBEDDED {
1060 public: 954 public:
1061 AllocationStats() { Clear(); } 955 AllocationStats() { Clear(); }
1062 956
1063 // Zero out all the allocation statistics (ie, no capacity). 957 // Zero out all the allocation statistics (ie, no capacity).
1064 void Clear() { 958 void Clear() {
1065 capacity_ = 0; 959 capacity_ = 0;
1066 available_ = 0;
1067 size_ = 0; 960 size_ = 0;
1068 waste_ = 0; 961 waste_ = 0;
1069 } 962 }
1070 963
1071 // Reset the allocation statistics (ie, available = capacity with no 964 // Reset the allocation statistics (ie, available = capacity with no
1072 // wasted or allocated bytes). 965 // wasted or allocated bytes).
1073 void Reset() { 966 void Reset() {
1074 available_ = capacity_;
1075 size_ = 0; 967 size_ = 0;
1076 waste_ = 0; 968 waste_ = 0;
1077 } 969 }
1078 970
1079 // Accessors for the allocation statistics. 971 // Accessors for the allocation statistics.
1080 intptr_t Capacity() { return capacity_; } 972 intptr_t Capacity() { return capacity_; }
1081 intptr_t Available() { return available_; }
1082 intptr_t Size() { return size_; } 973 intptr_t Size() { return size_; }
1083 intptr_t Waste() { return waste_; } 974 intptr_t Waste() { return waste_; }
1084 975
1085 // Grow the space by adding available bytes. 976 // Grow the space by adding available bytes. They are initially marked as
977 // being in use (part of the size), but will normally be immediately freed,
978 // putting them on the free list and removing them from size_.
1086 void ExpandSpace(int size_in_bytes) { 979 void ExpandSpace(int size_in_bytes) {
1087 capacity_ += size_in_bytes; 980 capacity_ += size_in_bytes;
1088 available_ += size_in_bytes; 981 size_ += size_in_bytes;
1089 }
1090
1091 // Shrink the space by removing available bytes.
1092 void ShrinkSpace(int size_in_bytes) {
1093 capacity_ -= size_in_bytes;
1094 available_ -= size_in_bytes;
1095 } 982 }
1096 983
1097 // Allocate from available bytes (available -> size). 984 // Allocate from available bytes (available -> size).
1098 void AllocateBytes(intptr_t size_in_bytes) { 985 void AllocateBytes(intptr_t size_in_bytes) {
1099 available_ -= size_in_bytes;
1100 size_ += size_in_bytes; 986 size_ += size_in_bytes;
1101 } 987 }
1102 988
1103 // Free allocated bytes, making them available (size -> available). 989 // Free allocated bytes, making them available (size -> available).
1104 void DeallocateBytes(intptr_t size_in_bytes) { 990 void DeallocateBytes(intptr_t size_in_bytes) {
1105 size_ -= size_in_bytes; 991 size_ -= size_in_bytes;
1106 available_ += size_in_bytes; 992 ASSERT(size_ >= 0);
1107 } 993 }
1108 994
1109 // Waste free bytes (available -> waste). 995 // Waste free bytes (available -> waste).
1110 void WasteBytes(int size_in_bytes) { 996 void WasteBytes(int size_in_bytes) {
1111 available_ -= size_in_bytes; 997 size_ -= size_in_bytes;
1112 waste_ += size_in_bytes; 998 waste_ += size_in_bytes;
1113 } 999 }
1114 1000
1115 // Consider the wasted bytes to be allocated, as they contain filler
1116 // objects (waste -> size).
1117 void FillWastedBytes(intptr_t size_in_bytes) {
1118 waste_ -= size_in_bytes;
1119 size_ += size_in_bytes;
1120 }
1121
1122 private: 1001 private:
1123 intptr_t capacity_; 1002 intptr_t capacity_;
1124 intptr_t available_;
1125 intptr_t size_; 1003 intptr_t size_;
1126 intptr_t waste_; 1004 intptr_t waste_;
1127 }; 1005 };
1128 1006
1129 1007
1008 // -----------------------------------------------------------------------------
1009 // Free lists for old object spaces
1010 //
1011 // Free-list nodes are free blocks in the heap. They look like heap objects
1012 // (free-list node pointers have the heap object tag, and they have a map like
1013 // a heap object). They have a size and a next pointer. The next pointer is
1014 // the raw address of the next free list node (or NULL).
1015 class FreeListNode: public HeapObject {
1016 public:
1017 // Obtain a free-list node from a raw address. This is not a cast because
1018 // it does not check nor require that the first word at the address is a map
1019 // pointer.
1020 static FreeListNode* FromAddress(Address address) {
1021 return reinterpret_cast<FreeListNode*>(HeapObject::FromAddress(address));
1022 }
1023
1024 static inline bool IsFreeListNode(HeapObject* object);
1025
1026 // Set the size in bytes, which can be read with HeapObject::Size(). This
1027 // function also writes a map to the first word of the block so that it
1028 // looks like a heap object to the garbage collector and heap iteration
1029 // functions.
1030 void set_size(int size_in_bytes);
1031
1032 // Accessors for the next field.
1033 inline FreeListNode* next();
1034 inline FreeListNode** next_address();
1035 inline void set_next(FreeListNode* next);
1036
1037 inline void Zap();
1038
1039 private:
1040 static const int kNextOffset = POINTER_SIZE_ALIGN(ByteArray::kHeaderSize);
1041
1042 DISALLOW_IMPLICIT_CONSTRUCTORS(FreeListNode);
1043 };
1044
1045
1046 static const uintptr_t kFreeListZapValue = 0xfeed1eaf;
Vyacheslav Egorov (Chromium) 2011/03/15 09:20:09 please move it to other zap values.
Erik Corry 2011/03/17 13:39:17 Done.
1047
1048
1049 // The free list for the old space. The free list is organized in such a way
1050 // as to encourage objects allocated around the same time to be near each
1051 // other. The normal way to allocate is intended to be by bumping a 'top'
1052 // pointer until it hits a 'limit' pointer. When the limit is hit we need to
1053 // find a new space to allocate from. This is done with the free list, which
1054 // is divided up into rough categories to cut down on waste. Having finer
1055 // categories would scatter allocation more.
1056
1057 // The old space free list is organized in categories.
1058 // 1-31 words: Such small free areas are discarded for efficiency reasons.
1059 // They can be reclaimed by the compactor. However the distance between top
1060 // and limit may be this small.
1061 // 32-255 words: There is a list of spaces this large. It is used for top and
1062 // limit when the object we need to allocate is 1-31 words in size. These
1063 // spaces are called small.
1064 // 256-2047 words: There is a list of spaces this large. It is used for top and
1065 // limit when the object we need to allocate is 32-255 words in size. These
1066 // spaces are called medium.
1067 // 1048-16383 words: There is a list of spaces this large. It is used for top
1068 // and limit when the object we need to allocate is 256-2047 words in size.
1069 // These spaces are call large.
1070 // At least 16384 words. This list is for objects of 2048 words or larger.
1071 // Empty pages are added to this list. These spaces are called huge.
1072 class OldSpaceFreeList BASE_EMBEDDED {
1073 public:
1074 explicit OldSpaceFreeList(PagedSpace* owner);
1075
1076 // Clear the free list.
1077 void Reset();
1078
1079 // Return the number of bytes available on the free list.
1080 intptr_t available() { return available_; }
1081
1082 // Place a node on the free list. The block of size 'size_in_bytes'
1083 // starting at 'start' is placed on the free list. The return value is the
1084 // number of bytes that have been lost due to internal fragmentation by
1085 // freeing the block. Bookkeeping information will be written to the block,
1086 // ie, its contents will be destroyed. The start address should be word
1087 // aligned, and the size should be a non-zero multiple of the word size.
1088 int Free(Address start, int size_in_bytes);
1089
1090 // Allocate a block of size 'size_in_bytes' from the free list. The block
1091 // is unitialized. A failure is returned if no block is available. The
1092 // number of bytes lost to fragmentation is returned in the output parameter
1093 // 'wasted_bytes'. The size should be a non-zero multiple of the word size.
1094 MUST_USE_RESULT HeapObject* Allocate(int size_in_bytes);
1095
1096 void MarkNodes();
1097
1098 #ifdef DEBUG
1099 void Zap();
1100 static intptr_t SumFreeList(FreeListNode* node);
1101 intptr_t SumFreeLists();
1102 #endif
1103
1104 private:
1105 // The size range of blocks, in bytes.
1106 static const int kMinBlockSize = 3 * kPointerSize;
1107 static const int kMaxBlockSize = Page::kMaxHeapObjectSize;
1108
1109 // The identity of the owning space.
1110 PagedSpace* owner_;
1111
1112 // Total available bytes in all blocks on this free list.
1113 int available_;
1114
1115 static const int kSmallListMin = 0x20 * kPointerSize;
1116 static const int kSmallListMax = 0xff * kPointerSize;
1117 static const int kMediumListMax = 0x7ff * kPointerSize;
1118 static const int kLargeListMax = 0x3fff * kPointerSize;
1119 static const int kSmallAllocationMax = kSmallListMin - kPointerSize;
1120 static const int kMediumAllocationMax = kSmallListMax;
1121 static const int kLargeAllocationMax = kMediumListMax;
1122 FreeListNode* small_list_;
1123 FreeListNode* medium_list_;
1124 FreeListNode* large_list_;
1125 FreeListNode* huge_list_;
1126
1127 DISALLOW_IMPLICIT_CONSTRUCTORS(OldSpaceFreeList);
1128 };
1129
1130
1130 class PagedSpace : public Space { 1131 class PagedSpace : public Space {
1131 public: 1132 public:
1132 // Creates a space with a maximum capacity, and an id. 1133 // Creates a space with a maximum capacity, and an id.
1133 PagedSpace(intptr_t max_capacity, 1134 PagedSpace(intptr_t max_capacity,
1134 AllocationSpace id, 1135 AllocationSpace id,
1135 Executability executable); 1136 Executability executable);
1136 1137
1137 virtual ~PagedSpace() {} 1138 virtual ~PagedSpace() {}
1138 1139
1139 // Set up the space using the given address range of virtual memory (from 1140 // Set up the space using the given address range of virtual memory (from
(...skipping 13 matching lines...) Expand all
1153 // Checks whether an object/address is in this space. 1154 // Checks whether an object/address is in this space.
1154 inline bool Contains(Address a); 1155 inline bool Contains(Address a);
1155 bool Contains(HeapObject* o) { return Contains(o->address()); } 1156 bool Contains(HeapObject* o) { return Contains(o->address()); }
1156 1157
1157 // Given an address occupied by a live object, return that object if it is 1158 // Given an address occupied by a live object, return that object if it is
1158 // in this space, or Failure::Exception() if it is not. The implementation 1159 // in this space, or Failure::Exception() if it is not. The implementation
1159 // iterates over objects in the page containing the address, the cost is 1160 // iterates over objects in the page containing the address, the cost is
1160 // linear in the number of objects in the page. It may be slow. 1161 // linear in the number of objects in the page. It may be slow.
1161 MUST_USE_RESULT MaybeObject* FindObject(Address addr); 1162 MUST_USE_RESULT MaybeObject* FindObject(Address addr);
1162 1163
1163 // Checks whether page is currently in use by this space.
1164 bool IsUsed(Page* page);
1165
1166 // Prepares for a mark-compact GC. 1164 // Prepares for a mark-compact GC.
1167 virtual void PrepareForMarkCompact(bool will_compact); 1165 virtual void PrepareForMarkCompact(bool will_compact);
1168 1166
1169 // The top of allocation in a page in this space. Undefined if page is unused. 1167 // Current capacity without growing (Size() + Available()).
1170 Address PageAllocationTop(Page* page) {
1171 return page == TopPageOf(allocation_info_) ? top()
1172 : PageAllocationLimit(page);
1173 }
1174
1175 // The limit of allocation for a page in this space.
1176 virtual Address PageAllocationLimit(Page* page) = 0;
1177
1178 void FlushTopPageWatermark() {
1179 AllocationTopPage()->SetCachedAllocationWatermark(top());
1180 AllocationTopPage()->InvalidateWatermark(true);
1181 }
1182
1183 // Current capacity without growing (Size() + Available() + Waste()).
1184 intptr_t Capacity() { return accounting_stats_.Capacity(); } 1168 intptr_t Capacity() { return accounting_stats_.Capacity(); }
1185 1169
1186 // Total amount of memory committed for this space. For paged 1170 // Total amount of memory committed for this space. For paged
1187 // spaces this equals the capacity. 1171 // spaces this equals the capacity.
1188 intptr_t CommittedMemory() { return Capacity(); } 1172 intptr_t CommittedMemory() { return Capacity(); }
1189 1173
1190 // Available bytes without growing. 1174 // Sets the capacity, the available space and the wasted space to zero.
1191 intptr_t Available() { return accounting_stats_.Available(); } 1175 // The stats are rebuilt during sweeping by adding each page to the
1176 // capacity and the size when it is encountered. As free spaces are
1177 // discovered during the sweeping they are subtracted from the size and added
1178 // to the available and wasted totals.
1179 void ClearStats() { accounting_stats_.Clear(); }
1192 1180
1193 // Allocated bytes in this space. 1181 // Available bytes without growing. These are the bytes on the free list.
1182 // The bytes in the linear allocation area are not included in this total
1183 // because updating the stats would slow down allocation. New pages are
1184 // immediately added to the free list so they show up here.
1185 intptr_t Available() { return free_list_.available(); }
1186
1187 // Allocated bytes in this space. Garbage bytes that were not found due to
1188 // lazy sweeping are counted as being allocated! The bytes in the current
1189 // linear allocation area (between top and limit) are also counted here.
1194 virtual intptr_t Size() { return accounting_stats_.Size(); } 1190 virtual intptr_t Size() { return accounting_stats_.Size(); }
1195 1191
1196 // Wasted bytes due to fragmentation and not recoverable until the 1192 // As size, but the bytes in the current linear allocation area are not
1197 // next GC of this space. 1193 // included.
1198 intptr_t Waste() { return accounting_stats_.Waste(); } 1194 virtual intptr_t SizeOfObjects() { return Size() - (limit() - top()); }
1199 1195
1200 // Returns the address of the first object in this space. 1196 // Wasted bytes in this space. These are just the bytes that were thrown away
1201 Address bottom() { return first_page_->ObjectAreaStart(); } 1197 // due to being too small to use for allocation. They do not include the
1198 // free bytes that were not found at all due to lazy sweeping.
1199 virtual intptr_t Waste() { return accounting_stats_.Waste(); }
1202 1200
1203 // Returns the allocation pointer in this space. 1201 // Returns the allocation pointer in this space.
1204 Address top() { return allocation_info_.top; } 1202 Address top() { return allocation_info_.top; }
1203 Address limit() { return allocation_info_.limit; }
1205 1204
1206 // Allocate the requested number of bytes in the space if possible, return a 1205 // Allocate the requested number of bytes in the space if possible, return a
1207 // failure object if not. 1206 // failure object if not.
1208 MUST_USE_RESULT inline MaybeObject* AllocateRaw(int size_in_bytes); 1207 MUST_USE_RESULT inline MaybeObject* AllocateRaw(int size_in_bytes);
1209 1208
1210 virtual bool ReserveSpace(int bytes); 1209 virtual bool ReserveSpace(int bytes);
1211 1210
1212 // Used by ReserveSpace. 1211 // Give a block of memory to the space's free list. It might be added to
1213 virtual void PutRestOfCurrentPageOnFreeList(Page* current_page) = 0; 1212 // the free list or accounted as waste.
1214 1213 // If add_to_freelist is false then just accounting stats are updated and
1215 // Free all pages in range from prev (exclusive) to last (inclusive). 1214 // no attempt to add area to free list is made.
1216 // Freed pages are moved to the end of page list. 1215 void Free(Address start, int size_in_bytes) {
1217 void FreePages(Page* prev, Page* last); 1216 int wasted = free_list_.Free(start, size_in_bytes);
1218 1217 accounting_stats_.DeallocateBytes(size_in_bytes - wasted);
1219 // Deallocates a block. 1218 }
1220 virtual void DeallocateBlock(Address start,
1221 int size_in_bytes,
1222 bool add_to_freelist) = 0;
1223 1219
1224 // Set space allocation info. 1220 // Set space allocation info.
1225 void SetTop(Address top) { 1221 void SetTop(Address top, Address limit) {
1222 ASSERT(top == limit ||
1223 Page::FromAddress(top) == Page::FromAddress(limit - 1));
1226 allocation_info_.top = top; 1224 allocation_info_.top = top;
1227 allocation_info_.limit = PageAllocationLimit(Page::FromAllocationTop(top)); 1225 allocation_info_.limit = limit;
1226 accounting_stats_.AllocateBytes(limit - top);
1227 }
1228
1229 void IncreaseCapacity(int size) {
1230 accounting_stats_.ExpandSpace(size);
1228 } 1231 }
1229 1232
1230 // Releases half of unused pages. 1233 // Releases half of unused pages.
1231 void Shrink(); 1234 void Shrink();
1232 1235
1233 // Ensures that the capacity is at least 'capacity'. Returns false on failure. 1236 // Ensures that the capacity is at least 'capacity'. Returns false on failure.
1234 bool EnsureCapacity(int capacity); 1237 bool EnsureCapacity(int capacity);
1235 1238
1239 // The dummy page that anchors the linked list of pages.
1240 Page *anchor() { return &anchor_; }
1241
1236 #ifdef ENABLE_HEAP_PROTECTION 1242 #ifdef ENABLE_HEAP_PROTECTION
1237 // Protect/unprotect the space by marking it read-only/writable. 1243 // Protect/unprotect the space by marking it read-only/writable.
1238 void Protect(); 1244 void Protect();
1239 void Unprotect(); 1245 void Unprotect();
1240 #endif 1246 #endif
1241 1247
1242 #ifdef DEBUG 1248 #ifdef DEBUG
1243 // Print meta info and objects in this space. 1249 // Print meta info and objects in this space.
1244 virtual void Print(); 1250 virtual void Print();
1245 1251
1246 // Verify integrity of this space. 1252 // Verify integrity of this space.
1247 virtual void Verify(ObjectVisitor* visitor); 1253 virtual void Verify(ObjectVisitor* visitor);
1248 1254
1255 // Reports statistics for the space
1256 void ReportStatistics();
1257
1249 // Overridden by subclasses to verify space-specific object 1258 // Overridden by subclasses to verify space-specific object
1250 // properties (e.g., only maps or free-list nodes are in map space). 1259 // properties (e.g., only maps or free-list nodes are in map space).
1251 virtual void VerifyObject(HeapObject* obj) {} 1260 virtual void VerifyObject(HeapObject* obj) {}
1252 1261
1253 // Report code object related statistics 1262 // Report code object related statistics
1254 void CollectCodeStatistics(); 1263 void CollectCodeStatistics();
1255 static void ReportCodeStatistics(); 1264 static void ReportCodeStatistics();
1256 static void ResetCodeStatistics(); 1265 static void ResetCodeStatistics();
1257 #endif 1266 #endif
1258 1267
1259 // Returns the page of the allocation pointer. 1268 bool was_swept_conservatively() { return was_swept_conservatively_; }
1260 Page* AllocationTopPage() { return TopPageOf(allocation_info_); } 1269 void set_was_swept_conservatively(bool b) { was_swept_conservatively_ = b; }
1261 1270
1262 protected: 1271 protected:
1263 // Maximum capacity of this space. 1272 // Maximum capacity of this space.
1264 intptr_t max_capacity_; 1273 intptr_t max_capacity_;
1265 1274
1266 // Accounting information for this space. 1275 // Accounting information for this space.
1267 AllocationStats accounting_stats_; 1276 AllocationStats accounting_stats_;
1268 1277
1269 // The first page in this space. 1278 // The dummy page that anchors the double linked list of pages.
1270 Page* first_page_; 1279 Page anchor_;
1271 1280
1272 // The last page in this space. Initially set in Setup, updated in 1281 // The space's free list.
1273 // Expand and Shrink. 1282 OldSpaceFreeList free_list_;
1274 Page* last_page_;
1275 1283
1276 // Normal allocation information. 1284 // Normal allocation information.
1277 AllocationInfo allocation_info_; 1285 AllocationInfo allocation_info_;
1278 1286
1279 // Bytes of each page that cannot be allocated. Possibly non-zero 1287 // Bytes of each page that cannot be allocated. Possibly non-zero
1280 // for pages in spaces with only fixed-size objects. Always zero 1288 // for pages in spaces with only fixed-size objects. Always zero
1281 // for pages in spaces with variable sized objects (those pages are 1289 // for pages in spaces with variable sized objects (those pages are
1282 // padded with free-list nodes). 1290 // padded with free-list nodes).
1283 int page_extra_; 1291 int page_extra_;
1284 1292
1285 // Sets allocation pointer to a page bottom. 1293 bool was_swept_conservatively_;
1286 static void SetAllocationInfo(AllocationInfo* alloc_info, Page* p);
1287 1294
1288 // Returns the top page specified by an allocation info structure. 1295 // Sets allocation pointer. If the allocation pointer already pointed to a
1289 static Page* TopPageOf(AllocationInfo alloc_info) { 1296 // non-zero-length area then that area may be returned to the free list.
1290 return Page::FromAllocationTop(alloc_info.limit); 1297 void SetAllocationInfo(Address start, Address end);
1291 }
1292
1293 int CountPagesToTop() {
1294 Page* p = Page::FromAllocationTop(allocation_info_.top);
1295 PageIterator it(this, PageIterator::ALL_PAGES);
1296 int counter = 1;
1297 while (it.has_next()) {
1298 if (it.next() == p) return counter;
1299 counter++;
1300 }
1301 UNREACHABLE();
1302 return -1;
1303 }
1304 1298
1305 // Expands the space by allocating a fixed number of pages. Returns false if 1299 // Expands the space by allocating a fixed number of pages. Returns false if
1306 // it cannot allocate requested number of pages from OS. 1300 // it cannot allocate requested number of pages from OS.
1307 bool Expand(); 1301 bool Expand();
1308 1302
1309 // Generic fast case allocation function that tries linear allocation in 1303 // Generic fast case allocation function that tries linear allocation at the
1310 // the top page of 'alloc_info'. Returns NULL on failure. 1304 // address denoted by top in allocation_info_.
1311 inline HeapObject* AllocateLinearly(AllocationInfo* alloc_info, 1305 inline HeapObject* AllocateLinearly(AllocationInfo* alloc_info,
1312 int size_in_bytes); 1306 int size_in_bytes);
1313 1307
1314 // During normal allocation or deserialization, roll to the next page in
1315 // the space (there is assumed to be one) and allocate there. This
1316 // function is space-dependent.
1317 virtual HeapObject* AllocateInNextPage(Page* current_page,
1318 int size_in_bytes) = 0;
1319
1320 // Slow path of AllocateRaw. This function is space-dependent. 1308 // Slow path of AllocateRaw. This function is space-dependent.
1321 MUST_USE_RESULT virtual HeapObject* SlowAllocateRaw(int size_in_bytes) = 0; 1309 MUST_USE_RESULT virtual HeapObject* SlowAllocateRaw(int size_in_bytes);
1322 1310
1323 #ifdef DEBUG 1311 #ifdef DEBUG
1324 // Returns the number of total pages in this space. 1312 // Returns the number of total pages in this space.
1325 int CountTotalPages(); 1313 int CountTotalPages();
1326 #endif 1314 #endif
1327 private: 1315 private:
1328 friend class PageIterator; 1316 friend class PageIterator;
1329 }; 1317 };
1330 1318
1331 1319
(...skipping 418 matching lines...) Expand 10 before | Expand all | Expand 10 after
1750 AllocationInfo* alloc_info); 1738 AllocationInfo* alloc_info);
1751 1739
1752 friend class SemiSpaceIterator; 1740 friend class SemiSpaceIterator;
1753 1741
1754 public: 1742 public:
1755 TRACK_MEMORY("NewSpace") 1743 TRACK_MEMORY("NewSpace")
1756 }; 1744 };
1757 1745
1758 1746
1759 // ----------------------------------------------------------------------------- 1747 // -----------------------------------------------------------------------------
1760 // Free lists for old object spaces
1761 //
1762 // Free-list nodes are free blocks in the heap. They look like heap objects
1763 // (free-list node pointers have the heap object tag, and they have a map like
1764 // a heap object). They have a size and a next pointer. The next pointer is
1765 // the raw address of the next free list node (or NULL).
1766 class FreeListNode: public HeapObject {
1767 public:
1768 // Obtain a free-list node from a raw address. This is not a cast because
1769 // it does not check nor require that the first word at the address is a map
1770 // pointer.
1771 static FreeListNode* FromAddress(Address address) {
1772 return reinterpret_cast<FreeListNode*>(HeapObject::FromAddress(address));
1773 }
1774
1775 static inline bool IsFreeListNode(HeapObject* object);
1776
1777 // Set the size in bytes, which can be read with HeapObject::Size(). This
1778 // function also writes a map to the first word of the block so that it
1779 // looks like a heap object to the garbage collector and heap iteration
1780 // functions.
1781 void set_size(int size_in_bytes);
1782
1783 // Accessors for the next field.
1784 inline Address next();
1785 inline void set_next(Address next);
1786
1787 inline void Zap();
1788
1789 private:
1790 static const int kNextOffset = POINTER_SIZE_ALIGN(ByteArray::kHeaderSize);
1791
1792 DISALLOW_IMPLICIT_CONSTRUCTORS(FreeListNode);
1793 };
1794
1795
1796 static const uintptr_t kFreeListZapValue = 0xfeed1eaf;
1797
1798
1799 // The free list for the old space.
1800 class OldSpaceFreeList BASE_EMBEDDED {
1801 public:
1802 explicit OldSpaceFreeList(AllocationSpace owner);
1803
1804 // Clear the free list.
1805 void Reset();
1806
1807 // Return the number of bytes available on the free list.
1808 intptr_t available() { return available_; }
1809
1810 // Place a node on the free list. The block of size 'size_in_bytes'
1811 // starting at 'start' is placed on the free list. The return value is the
1812 // number of bytes that have been lost due to internal fragmentation by
1813 // freeing the block. Bookkeeping information will be written to the block,
1814 // ie, its contents will be destroyed. The start address should be word
1815 // aligned, and the size should be a non-zero multiple of the word size.
1816 int Free(Address start, int size_in_bytes);
1817
1818 // Allocate a block of size 'size_in_bytes' from the free list. The block
1819 // is unitialized. A failure is returned if no block is available. The
1820 // number of bytes lost to fragmentation is returned in the output parameter
1821 // 'wasted_bytes'. The size should be a non-zero multiple of the word size.
1822 MUST_USE_RESULT MaybeObject* Allocate(int size_in_bytes, int* wasted_bytes);
1823
1824 void MarkNodes();
1825
1826 #ifdef DEBUG
1827 void Zap();
1828 #endif
1829
1830 private:
1831 // The size range of blocks, in bytes. (Smaller allocations are allowed, but
1832 // will always result in waste.)
1833 static const int kMinBlockSize = 2 * kPointerSize;
1834 static const int kMaxBlockSize = Page::kMaxHeapObjectSize;
1835
1836 // The identity of the owning space, for building allocation Failure
1837 // objects.
1838 AllocationSpace owner_;
1839
1840 // Total available bytes in all blocks on this free list.
1841 int available_;
1842
1843 // Blocks are put on exact free lists in an array, indexed by size in words.
1844 // The available sizes are kept in an increasingly ordered list. Entries
1845 // corresponding to sizes < kMinBlockSize always have an empty free list
1846 // (but index kHead is used for the head of the size list).
1847 struct SizeNode {
1848 // Address of the head FreeListNode of the implied block size or NULL.
1849 Address head_node_;
1850 // Size (words) of the next larger available size if head_node_ != NULL.
1851 int next_size_;
1852 };
1853 static const int kFreeListsLength = kMaxBlockSize / kPointerSize + 1;
1854 SizeNode free_[kFreeListsLength];
1855
1856 // Sentinel elements for the size list. Real elements are in ]kHead..kEnd[.
1857 static const int kHead = kMinBlockSize / kPointerSize - 1;
1858 static const int kEnd = kMaxInt;
1859
1860 // We keep a "finger" in the size list to speed up a common pattern:
1861 // repeated requests for the same or increasing sizes.
1862 int finger_;
1863
1864 // Starting from *prev, find and return the smallest size >= index (words),
1865 // or kEnd. Update *prev to be the largest size < index, or kHead.
1866 int FindSize(int index, int* prev) {
1867 int cur = free_[*prev].next_size_;
1868 while (cur < index) {
1869 *prev = cur;
1870 cur = free_[cur].next_size_;
1871 }
1872 return cur;
1873 }
1874
1875 // Remove an existing element from the size list.
1876 void RemoveSize(int index) {
1877 int prev = kHead;
1878 int cur = FindSize(index, &prev);
1879 ASSERT(cur == index);
1880 free_[prev].next_size_ = free_[cur].next_size_;
1881 finger_ = prev;
1882 }
1883
1884 // Insert a new element into the size list.
1885 void InsertSize(int index) {
1886 int prev = kHead;
1887 int cur = FindSize(index, &prev);
1888 ASSERT(cur != index);
1889 free_[prev].next_size_ = index;
1890 free_[index].next_size_ = cur;
1891 }
1892
1893 // The size list is not updated during a sequence of calls to Free, but is
1894 // rebuilt before the next allocation.
1895 void RebuildSizeList();
1896 bool needs_rebuild_;
1897
1898 #ifdef DEBUG
1899 // Does this free list contain a free block located at the address of 'node'?
1900 bool Contains(FreeListNode* node);
1901 #endif
1902
1903 DISALLOW_COPY_AND_ASSIGN(OldSpaceFreeList);
1904 };
1905
1906
1907 // The free list for the map space.
1908 class FixedSizeFreeList BASE_EMBEDDED {
1909 public:
1910 FixedSizeFreeList(AllocationSpace owner, int object_size);
1911
1912 // Clear the free list.
1913 void Reset();
1914
1915 // Return the number of bytes available on the free list.
1916 intptr_t available() { return available_; }
1917
1918 // Place a node on the free list. The block starting at 'start' (assumed to
1919 // have size object_size_) is placed on the free list. Bookkeeping
1920 // information will be written to the block, ie, its contents will be
1921 // destroyed. The start address should be word aligned.
1922 void Free(Address start);
1923
1924 // Allocate a fixed sized block from the free list. The block is unitialized.
1925 // A failure is returned if no block is available.
1926 MUST_USE_RESULT MaybeObject* Allocate();
1927
1928 void MarkNodes();
1929
1930 #ifdef DEBUG
1931 void Zap();
1932 #endif
1933
1934 private:
1935 // Available bytes on the free list.
1936 intptr_t available_;
1937
1938 // The head of the free list.
1939 Address head_;
1940
1941 // The tail of the free list.
1942 Address tail_;
1943
1944 // The identity of the owning space, for building allocation Failure
1945 // objects.
1946 AllocationSpace owner_;
1947
1948 // The size of the objects in this space.
1949 int object_size_;
1950
1951 DISALLOW_COPY_AND_ASSIGN(FixedSizeFreeList);
1952 };
1953
1954
1955 // -----------------------------------------------------------------------------
1956 // Old object space (excluding map objects) 1748 // Old object space (excluding map objects)
1957 1749
1958 class OldSpace : public PagedSpace { 1750 class OldSpace : public PagedSpace {
1959 public: 1751 public:
1960 // Creates an old space object with a given maximum capacity. 1752 // Creates an old space object with a given maximum capacity.
1961 // The constructor does not allocate pages from OS. 1753 // The constructor does not allocate pages from OS.
1962 explicit OldSpace(intptr_t max_capacity, 1754 explicit OldSpace(intptr_t max_capacity,
1963 AllocationSpace id, 1755 AllocationSpace id,
1964 Executability executable) 1756 Executability executable)
1965 : PagedSpace(max_capacity, id, executable), free_list_(id) { 1757 : PagedSpace(max_capacity, id, executable) {
1966 page_extra_ = 0; 1758 page_extra_ = 0;
1967 } 1759 }
1968 1760
1969 // The bytes available on the free list (ie, not above the linear allocation
1970 // pointer).
1971 intptr_t AvailableFree() { return free_list_.available(); }
1972
1973 // The limit of allocation for a page in this space. 1761 // The limit of allocation for a page in this space.
1974 virtual Address PageAllocationLimit(Page* page) { 1762 virtual Address PageAllocationLimit(Page* page) {
1975 return page->ObjectAreaEnd(); 1763 return page->ObjectAreaEnd();
1976 } 1764 }
1977 1765
1978 // Give a block of memory to the space's free list. It might be added to
1979 // the free list or accounted as waste.
1980 // If add_to_freelist is false then just accounting stats are updated and
1981 // no attempt to add area to free list is made.
1982 void Free(Address start, int size_in_bytes, bool add_to_freelist) {
1983 accounting_stats_.DeallocateBytes(size_in_bytes);
1984
1985 if (add_to_freelist) {
1986 int wasted_bytes = free_list_.Free(start, size_in_bytes);
1987 accounting_stats_.WasteBytes(wasted_bytes);
1988 }
1989 }
1990
1991 virtual void DeallocateBlock(Address start,
1992 int size_in_bytes,
1993 bool add_to_freelist);
1994
1995 // Prepare for full garbage collection. Resets the relocation pointer and 1766 // Prepare for full garbage collection. Resets the relocation pointer and
1996 // clears the free list. 1767 // clears the free list.
1997 virtual void PrepareForMarkCompact(bool will_compact); 1768 virtual void PrepareForMarkCompact(bool will_compact);
1998 1769
1999 virtual void PutRestOfCurrentPageOnFreeList(Page* current_page);
2000
2001 void MarkFreeListNodes() { free_list_.MarkNodes(); }
2002
2003 #ifdef DEBUG
2004 // Reports statistics for the space
2005 void ReportStatistics();
2006
2007 OldSpaceFreeList* free_list() { return &free_list_; }
2008 #endif
2009
2010 protected:
2011 // Virtual function in the superclass. Slow path of AllocateRaw.
2012 MUST_USE_RESULT HeapObject* SlowAllocateRaw(int size_in_bytes);
2013
2014 // Virtual function in the superclass. Allocate linearly at the start of
2015 // the page after current_page (there is assumed to be one).
2016 HeapObject* AllocateInNextPage(Page* current_page, int size_in_bytes);
2017
2018 private:
2019 // The space's free list.
2020 OldSpaceFreeList free_list_;
2021
2022 public: 1770 public:
2023 TRACK_MEMORY("OldSpace") 1771 TRACK_MEMORY("OldSpace")
2024 }; 1772 };
2025 1773
2026 1774
2027 // ----------------------------------------------------------------------------- 1775 // -----------------------------------------------------------------------------
2028 // Old space for objects of a fixed size 1776 // Old space for objects of a fixed size
2029 1777
2030 class FixedSpace : public PagedSpace { 1778 class FixedSpace : public PagedSpace {
2031 public: 1779 public:
2032 FixedSpace(intptr_t max_capacity, 1780 FixedSpace(intptr_t max_capacity,
2033 AllocationSpace id, 1781 AllocationSpace id,
2034 int object_size_in_bytes, 1782 int object_size_in_bytes,
2035 const char* name) 1783 const char* name)
2036 : PagedSpace(max_capacity, id, NOT_EXECUTABLE), 1784 : PagedSpace(max_capacity, id, NOT_EXECUTABLE),
2037 object_size_in_bytes_(object_size_in_bytes), 1785 object_size_in_bytes_(object_size_in_bytes),
2038 name_(name), 1786 name_(name) {
2039 free_list_(id, object_size_in_bytes) {
2040 page_extra_ = Page::kObjectAreaSize % object_size_in_bytes; 1787 page_extra_ = Page::kObjectAreaSize % object_size_in_bytes;
2041 } 1788 }
2042 1789
2043 // The limit of allocation for a page in this space. 1790 // The limit of allocation for a page in this space.
2044 virtual Address PageAllocationLimit(Page* page) { 1791 virtual Address PageAllocationLimit(Page* page) {
2045 return page->ObjectAreaEnd() - page_extra_; 1792 return page->ObjectAreaEnd() - page_extra_;
2046 } 1793 }
2047 1794
2048 int object_size_in_bytes() { return object_size_in_bytes_; } 1795 int object_size_in_bytes() { return object_size_in_bytes_; }
2049 1796
2050 // Give a fixed sized block of memory to the space's free list.
2051 // If add_to_freelist is false then just accounting stats are updated and
2052 // no attempt to add area to free list is made.
2053 void Free(Address start, bool add_to_freelist) {
2054 if (add_to_freelist) {
2055 free_list_.Free(start);
2056 }
2057 accounting_stats_.DeallocateBytes(object_size_in_bytes_);
2058 }
2059
2060 // Prepares for a mark-compact GC. 1797 // Prepares for a mark-compact GC.
2061 virtual void PrepareForMarkCompact(bool will_compact); 1798 virtual void PrepareForMarkCompact(bool will_compact);
2062 1799
2063 virtual void PutRestOfCurrentPageOnFreeList(Page* current_page);
2064
2065 virtual void DeallocateBlock(Address start,
2066 int size_in_bytes,
2067 bool add_to_freelist);
2068
2069 void MarkFreeListNodes() { free_list_.MarkNodes(); } 1800 void MarkFreeListNodes() { free_list_.MarkNodes(); }
2070 1801
2071 #ifdef DEBUG
2072 // Reports statistic info of the space
2073 void ReportStatistics();
2074
2075 FixedSizeFreeList* free_list() { return &free_list_; }
2076 #endif
2077
2078 protected: 1802 protected:
2079 // Virtual function in the superclass. Slow path of AllocateRaw.
2080 MUST_USE_RESULT HeapObject* SlowAllocateRaw(int size_in_bytes);
2081
2082 // Virtual function in the superclass. Allocate linearly at the start of
2083 // the page after current_page (there is assumed to be one).
2084 HeapObject* AllocateInNextPage(Page* current_page, int size_in_bytes);
2085
2086 void ResetFreeList() { 1803 void ResetFreeList() {
2087 free_list_.Reset(); 1804 free_list_.Reset();
2088 } 1805 }
2089 1806
2090 private: 1807 private:
2091 // The size of objects in this space. 1808 // The size of objects in this space.
2092 int object_size_in_bytes_; 1809 int object_size_in_bytes_;
2093 1810
2094 // The name of this space. 1811 // The name of this space.
2095 const char* name_; 1812 const char* name_;
2096
2097 // The space's free list.
2098 FixedSizeFreeList free_list_;
2099 }; 1813 };
2100 1814
2101 1815
2102 // ----------------------------------------------------------------------------- 1816 // -----------------------------------------------------------------------------
2103 // Old space for all map objects 1817 // Old space for all map objects
2104 1818
2105 class MapSpace : public FixedSpace { 1819 class MapSpace : public FixedSpace {
2106 public: 1820 public:
2107 // Creates a map space object with a maximum capacity. 1821 // Creates a map space object with a maximum capacity.
2108 MapSpace(intptr_t max_capacity, int max_map_space_pages, AllocationSpace id) 1822 MapSpace(intptr_t max_capacity, int max_map_space_pages, AllocationSpace id)
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after
2287 2001
2288 private: 2002 private:
2289 LargePage* current_; 2003 LargePage* current_;
2290 HeapObjectCallback size_func_; 2004 HeapObjectCallback size_func_;
2291 }; 2005 };
2292 2006
2293 2007
2294 } } // namespace v8::internal 2008 } } // namespace v8::internal
2295 2009
2296 #endif // V8_SPACES_H_ 2010 #endif // V8_SPACES_H_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698