1// Copyright 2011 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6//     * Redistributions of source code must retain the above copyright
7//       notice, this list of conditions and the following disclaimer.
8//     * Redistributions in binary form must reproduce the above
9//       copyright notice, this list of conditions and the following
10//       disclaimer in the documentation and/or other materials provided
11//       with the distribution.
12//     * Neither the name of Google Inc. nor the names of its
13//       contributors may be used to endorse or promote products derived
14//       from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#ifndef V8_SPACES_H_
29#define V8_SPACES_H_
30
31#include "allocation.h"
32#include "hashmap.h"
33#include "list.h"
34#include "log.h"
35#include "platform/mutex.h"
36#include "v8utils.h"
37
38namespace v8 {
39namespace internal {
40
41class Isolate;
42
43// -----------------------------------------------------------------------------
44// Heap structures:
45//
46// A JS heap consists of a young generation, an old generation, and a large
47// object space. The young generation is divided into two semispaces. A
48// scavenger implements Cheney's copying algorithm. The old generation is
49// separated into a map space and an old object space. The map space contains
50// all (and only) map objects, the rest of old objects go into the old space.
51// The old generation is collected by a mark-sweep-compact collector.
52//
53// The semispaces of the young generation are contiguous.  The old and map
54// spaces consists of a list of pages. A page has a page header and an object
55// area.
56//
57// There is a separate large object space for objects larger than
58// Page::kMaxHeapObjectSize, so that they do not have to move during
59// collection. The large object space is paged. Pages in large object space
60// may be larger than the page size.
61//
62// A store-buffer based write barrier is used to keep track of intergenerational
63// references.  See store-buffer.h.
64//
65// During scavenges and mark-sweep collections we sometimes (after a store
66// buffer overflow) iterate intergenerational pointers without decoding heap
67// object maps so if the page belongs to old pointer space or large object
68// space it is essential to guarantee that the page does not contain any
69// garbage pointers to new space: every pointer aligned word which satisfies
70// the Heap::InNewSpace() predicate must be a pointer to a live heap object in
71// new space. Thus objects in old pointer and large object spaces should have a
72// special layout (e.g. no bare integer fields). This requirement does not
73// apply to map space which is iterated in a special fashion. However we still
74// require pointer fields of dead maps to be cleaned.
75//
76// To enable lazy cleaning of old space pages we can mark chunks of the page
77// as being garbage.  Garbage sections are marked with a special map.  These
78// sections are skipped when scanning the page, even if we are otherwise
79// scanning without regard for object boundaries.  Garbage sections are chained
80// together to form a free list after a GC.  Garbage sections created outside
81// of GCs by object trunctation etc. may not be in the free list chain.  Very
82// small free spaces are ignored, they need only be cleaned of bogus pointers
83// into new space.
84//
85// Each page may have up to one special garbage section.  The start of this
86// section is denoted by the top field in the space.  The end of the section
87// is denoted by the limit field in the space.  This special garbage section
88// is not marked with a free space map in the data.  The point of this section
89// is to enable linear allocation without having to constantly update the byte
90// array every time the top field is updated and a new object is created.  The
91// special garbage section is not in the chain of garbage sections.
92//
93// Since the top and limit fields are in the space, not the page, only one page
94// has a special garbage section, and if the top and limit are equal then there
95// is no special garbage section.
96
97// Some assertion macros used in the debugging mode.
98
99#define ASSERT_PAGE_ALIGNED(address)                                           \
100  ASSERT((OffsetFrom(address) & Page::kPageAlignmentMask) == 0)
101
102#define ASSERT_OBJECT_ALIGNED(address)                                         \
103  ASSERT((OffsetFrom(address) & kObjectAlignmentMask) == 0)
104
105#define ASSERT_OBJECT_SIZE(size)                                               \
106  ASSERT((0 < size) && (size <= Page::kMaxNonCodeHeapObjectSize))
107
108#define ASSERT_PAGE_OFFSET(offset)                                             \
109  ASSERT((Page::kObjectStartOffset <= offset)                                  \
110      && (offset <= Page::kPageSize))
111
112#define ASSERT_MAP_PAGE_INDEX(index)                                           \
113  ASSERT((0 <= index) && (index <= MapSpace::kMaxMapPageIndex))
114
115
116class PagedSpace;
117class MemoryAllocator;
118class AllocationInfo;
119class Space;
120class FreeList;
121class MemoryChunk;
122
123class MarkBit {
124 public:
125  typedef uint32_t CellType;
126
127  inline MarkBit(CellType* cell, CellType mask, bool data_only)
128      : cell_(cell), mask_(mask), data_only_(data_only) { }
129
130  inline CellType* cell() { return cell_; }
131  inline CellType mask() { return mask_; }
132
133#ifdef DEBUG
134  bool operator==(const MarkBit& other) {
135    return cell_ == other.cell_ && mask_ == other.mask_;
136  }
137#endif
138
139  inline void Set() { *cell_ |= mask_; }
140  inline bool Get() { return (*cell_ & mask_) != 0; }
141  inline void Clear() { *cell_ &= ~mask_; }
142
143  inline bool data_only() { return data_only_; }
144
145  inline MarkBit Next() {
146    CellType new_mask = mask_ << 1;
147    if (new_mask == 0) {
148      return MarkBit(cell_ + 1, 1, data_only_);
149    } else {
150      return MarkBit(cell_, new_mask, data_only_);
151    }
152  }
153
154 private:
155  CellType* cell_;
156  CellType mask_;
157  // This boolean indicates that the object is in a data-only space with no
158  // pointers.  This enables some optimizations when marking.
159  // It is expected that this field is inlined and turned into control flow
160  // at the place where the MarkBit object is created.
161  bool data_only_;
162};
163
164
165// Bitmap is a sequence of cells each containing fixed number of bits.
166class Bitmap {
167 public:
168  static const uint32_t kBitsPerCell = 32;
169  static const uint32_t kBitsPerCellLog2 = 5;
170  static const uint32_t kBitIndexMask = kBitsPerCell - 1;
171  static const uint32_t kBytesPerCell = kBitsPerCell / kBitsPerByte;
172  static const uint32_t kBytesPerCellLog2 = kBitsPerCellLog2 - kBitsPerByteLog2;
173
174  static const size_t kLength =
175    (1 << kPageSizeBits) >> (kPointerSizeLog2);
176
177  static const size_t kSize =
178    (1 << kPageSizeBits) >> (kPointerSizeLog2 + kBitsPerByteLog2);
179
180
181  static int CellsForLength(int length) {
182    return (length + kBitsPerCell - 1) >> kBitsPerCellLog2;
183  }
184
185  int CellsCount() {
186    return CellsForLength(kLength);
187  }
188
189  static int SizeFor(int cells_count) {
190    return sizeof(MarkBit::CellType) * cells_count;
191  }
192
193  INLINE(static uint32_t IndexToCell(uint32_t index)) {
194    return index >> kBitsPerCellLog2;
195  }
196
197  INLINE(static uint32_t CellToIndex(uint32_t index)) {
198    return index << kBitsPerCellLog2;
199  }
200
201  INLINE(static uint32_t CellAlignIndex(uint32_t index)) {
202    return (index + kBitIndexMask) & ~kBitIndexMask;
203  }
204
205  INLINE(MarkBit::CellType* cells()) {
206    return reinterpret_cast<MarkBit::CellType*>(this);
207  }
208
209  INLINE(Address address()) {
210    return reinterpret_cast<Address>(this);
211  }
212
213  INLINE(static Bitmap* FromAddress(Address addr)) {
214    return reinterpret_cast<Bitmap*>(addr);
215  }
216
217  inline MarkBit MarkBitFromIndex(uint32_t index, bool data_only = false) {
218    MarkBit::CellType mask = 1 << (index & kBitIndexMask);
219    MarkBit::CellType* cell = this->cells() + (index >> kBitsPerCellLog2);
220    return MarkBit(cell, mask, data_only);
221  }
222
223  static inline void Clear(MemoryChunk* chunk);
224
225  static void PrintWord(uint32_t word, uint32_t himask = 0) {
226    for (uint32_t mask = 1; mask != 0; mask <<= 1) {
227      if ((mask & himask) != 0) PrintF("[");
228      PrintF((mask & word) ? "1" : "0");
229      if ((mask & himask) != 0) PrintF("]");
230    }
231  }
232
233  class CellPrinter {
234   public:
235    CellPrinter() : seq_start(0), seq_type(0), seq_length(0) { }
236
237    void Print(uint32_t pos, uint32_t cell) {
238      if (cell == seq_type) {
239        seq_length++;
240        return;
241      }
242
243      Flush();
244
245      if (IsSeq(cell)) {
246        seq_start = pos;
247        seq_length = 0;
248        seq_type = cell;
249        return;
250      }
251
252      PrintF("%d: ", pos);
253      PrintWord(cell);
254      PrintF("\n");
255    }
256
257    void Flush() {
258      if (seq_length > 0) {
259        PrintF("%d: %dx%d\n",
260               seq_start,
261               seq_type == 0 ? 0 : 1,
262               seq_length * kBitsPerCell);
263        seq_length = 0;
264      }
265    }
266
267    static bool IsSeq(uint32_t cell) { return cell == 0 || cell == 0xFFFFFFFF; }
268
269   private:
270    uint32_t seq_start;
271    uint32_t seq_type;
272    uint32_t seq_length;
273  };
274
275  void Print() {
276    CellPrinter printer;
277    for (int i = 0; i < CellsCount(); i++) {
278      printer.Print(i, cells()[i]);
279    }
280    printer.Flush();
281    PrintF("\n");
282  }
283
284  bool IsClean() {
285    for (int i = 0; i < CellsCount(); i++) {
286      if (cells()[i] != 0) {
287        return false;
288      }
289    }
290    return true;
291  }
292};
293
294
295class SkipList;
296class SlotsBuffer;
297
298// MemoryChunk represents a memory region owned by a specific space.
299// It is divided into the header and the body. Chunk start is always
300// 1MB aligned. Start of the body is aligned so it can accommodate
301// any heap object.
302class MemoryChunk {
303 public:
304  // Only works if the pointer is in the first kPageSize of the MemoryChunk.
305  static MemoryChunk* FromAddress(Address a) {
306    return reinterpret_cast<MemoryChunk*>(OffsetFrom(a) & ~kAlignmentMask);
307  }
308
309  // Only works for addresses in pointer spaces, not data or code spaces.
310  static inline MemoryChunk* FromAnyPointerAddress(Heap* heap, Address addr);
311
312  Address address() { return reinterpret_cast<Address>(this); }
313
314  bool is_valid() { return address() != NULL; }
315
316  MemoryChunk* next_chunk() const { return next_chunk_; }
317  MemoryChunk* prev_chunk() const { return prev_chunk_; }
318
319  void set_next_chunk(MemoryChunk* next) { next_chunk_ = next; }
320  void set_prev_chunk(MemoryChunk* prev) { prev_chunk_ = prev; }
321
322  Space* owner() const {
323    if ((reinterpret_cast<intptr_t>(owner_) & kFailureTagMask) ==
324        kFailureTag) {
325      return reinterpret_cast<Space*>(reinterpret_cast<intptr_t>(owner_) -
326                                      kFailureTag);
327    } else {
328      return NULL;
329    }
330  }
331
332  void set_owner(Space* space) {
333    ASSERT((reinterpret_cast<intptr_t>(space) & kFailureTagMask) == 0);
334    owner_ = reinterpret_cast<Address>(space) + kFailureTag;
335    ASSERT((reinterpret_cast<intptr_t>(owner_) & kFailureTagMask) ==
336           kFailureTag);
337  }
338
339  VirtualMemory* reserved_memory() {
340    return &reservation_;
341  }
342
343  void InitializeReservedMemory() {
344    reservation_.Reset();
345  }
346
347  void set_reserved_memory(VirtualMemory* reservation) {
348    ASSERT_NOT_NULL(reservation);
349    reservation_.TakeControl(reservation);
350  }
351
352  bool scan_on_scavenge() { return IsFlagSet(SCAN_ON_SCAVENGE); }
353  void initialize_scan_on_scavenge(bool scan) {
354    if (scan) {
355      SetFlag(SCAN_ON_SCAVENGE);
356    } else {
357      ClearFlag(SCAN_ON_SCAVENGE);
358    }
359  }
360  inline void set_scan_on_scavenge(bool scan);
361
362  int store_buffer_counter() { return store_buffer_counter_; }
363  void set_store_buffer_counter(int counter) {
364    store_buffer_counter_ = counter;
365  }
366
367  bool Contains(Address addr) {
368    return addr >= area_start() && addr < area_end();
369  }
370
371  // Checks whether addr can be a limit of addresses in this page.
372  // It's a limit if it's in the page, or if it's just after the
373  // last byte of the page.
374  bool ContainsLimit(Address addr) {
375    return addr >= area_start() && addr <= area_end();
376  }
377
378  // Every n write barrier invocations we go to runtime even though
379  // we could have handled it in generated code.  This lets us check
380  // whether we have hit the limit and should do some more marking.
381  static const int kWriteBarrierCounterGranularity = 500;
382
383  enum MemoryChunkFlags {
384    IS_EXECUTABLE,
385    ABOUT_TO_BE_FREED,
386    POINTERS_TO_HERE_ARE_INTERESTING,
387    POINTERS_FROM_HERE_ARE_INTERESTING,
388    SCAN_ON_SCAVENGE,
389    IN_FROM_SPACE,  // Mutually exclusive with IN_TO_SPACE.
390    IN_TO_SPACE,    // All pages in new space has one of these two set.
391    NEW_SPACE_BELOW_AGE_MARK,
392    CONTAINS_ONLY_DATA,
393    EVACUATION_CANDIDATE,
394    RESCAN_ON_EVACUATION,
395
396    // Pages swept precisely can be iterated, hitting only the live objects.
397    // Whereas those swept conservatively cannot be iterated over. Both flags
398    // indicate that marking bits have been cleared by the sweeper, otherwise
399    // marking bits are still intact.
400    WAS_SWEPT_PRECISELY,
401    WAS_SWEPT_CONSERVATIVELY,
402
403    // Large objects can have a progress bar in their page header. These object
404    // are scanned in increments and will be kept black while being scanned.
405    // Even if the mutator writes to them they will be kept black and a white
406    // to grey transition is performed in the value.
407    HAS_PROGRESS_BAR,
408
409    // Last flag, keep at bottom.
410    NUM_MEMORY_CHUNK_FLAGS
411  };
412
413
414  static const int kPointersToHereAreInterestingMask =
415      1 << POINTERS_TO_HERE_ARE_INTERESTING;
416
417  static const int kPointersFromHereAreInterestingMask =
418      1 << POINTERS_FROM_HERE_ARE_INTERESTING;
419
420  static const int kEvacuationCandidateMask =
421      1 << EVACUATION_CANDIDATE;
422
423  static const int kSkipEvacuationSlotsRecordingMask =
424      (1 << EVACUATION_CANDIDATE) |
425      (1 << RESCAN_ON_EVACUATION) |
426      (1 << IN_FROM_SPACE) |
427      (1 << IN_TO_SPACE);
428
429
430  void SetFlag(int flag) {
431    flags_ |= static_cast<uintptr_t>(1) << flag;
432  }
433
434  void ClearFlag(int flag) {
435    flags_ &= ~(static_cast<uintptr_t>(1) << flag);
436  }
437
438  void SetFlagTo(int flag, bool value) {
439    if (value) {
440      SetFlag(flag);
441    } else {
442      ClearFlag(flag);
443    }
444  }
445
446  bool IsFlagSet(int flag) {
447    return (flags_ & (static_cast<uintptr_t>(1) << flag)) != 0;
448  }
449
450  // Set or clear multiple flags at a time. The flags in the mask
451  // are set to the value in "flags", the rest retain the current value
452  // in flags_.
453  void SetFlags(intptr_t flags, intptr_t mask) {
454    flags_ = (flags_ & ~mask) | (flags & mask);
455  }
456
457  // Return all current flags.
458  intptr_t GetFlags() { return flags_; }
459
460  intptr_t parallel_sweeping() const {
461    return parallel_sweeping_;
462  }
463
464  void set_parallel_sweeping(intptr_t state) {
465    parallel_sweeping_ = state;
466  }
467
468  bool TryParallelSweeping() {
469    return NoBarrier_CompareAndSwap(&parallel_sweeping_, 1, 0) == 1;
470  }
471
472  // Manage live byte count (count of bytes known to be live,
473  // because they are marked black).
474  void ResetLiveBytes() {
475    if (FLAG_gc_verbose) {
476      PrintF("ResetLiveBytes:%p:%x->0\n",
477             static_cast<void*>(this), live_byte_count_);
478    }
479    live_byte_count_ = 0;
480  }
481  void IncrementLiveBytes(int by) {
482    if (FLAG_gc_verbose) {
483      printf("UpdateLiveBytes:%p:%x%c=%x->%x\n",
484             static_cast<void*>(this), live_byte_count_,
485             ((by < 0) ? '-' : '+'), ((by < 0) ? -by : by),
486             live_byte_count_ + by);
487    }
488    live_byte_count_ += by;
489    ASSERT_LE(static_cast<unsigned>(live_byte_count_), size_);
490  }
491  int LiveBytes() {
492    ASSERT(static_cast<unsigned>(live_byte_count_) <= size_);
493    return live_byte_count_;
494  }
495
496  int write_barrier_counter() {
497    return static_cast<int>(write_barrier_counter_);
498  }
499
500  void set_write_barrier_counter(int counter) {
501    write_barrier_counter_ = counter;
502  }
503
504  int progress_bar() {
505    ASSERT(IsFlagSet(HAS_PROGRESS_BAR));
506    return progress_bar_;
507  }
508
509  void set_progress_bar(int progress_bar) {
510    ASSERT(IsFlagSet(HAS_PROGRESS_BAR));
511    progress_bar_ = progress_bar;
512  }
513
514  void ResetProgressBar() {
515    if (IsFlagSet(MemoryChunk::HAS_PROGRESS_BAR)) {
516      set_progress_bar(0);
517      ClearFlag(MemoryChunk::HAS_PROGRESS_BAR);
518    }
519  }
520
521  bool IsLeftOfProgressBar(Object** slot) {
522    Address slot_address = reinterpret_cast<Address>(slot);
523    ASSERT(slot_address > this->address());
524    return (slot_address - (this->address() + kObjectStartOffset)) <
525           progress_bar();
526  }
527
528  static void IncrementLiveBytesFromGC(Address address, int by) {
529    MemoryChunk::FromAddress(address)->IncrementLiveBytes(by);
530  }
531
532  static void IncrementLiveBytesFromMutator(Address address, int by);
533
534  static const intptr_t kAlignment =
535      (static_cast<uintptr_t>(1) << kPageSizeBits);
536
537  static const intptr_t kAlignmentMask = kAlignment - 1;
538
539  static const intptr_t kSizeOffset = kPointerSize + kPointerSize;
540
541  static const intptr_t kLiveBytesOffset =
542     kSizeOffset + kPointerSize + kPointerSize + kPointerSize +
543     kPointerSize + kPointerSize +
544     kPointerSize + kPointerSize + kPointerSize + kIntSize;
545
546  static const size_t kSlotsBufferOffset = kLiveBytesOffset + kIntSize;
547
548  static const size_t kWriteBarrierCounterOffset =
549      kSlotsBufferOffset + kPointerSize + kPointerSize;
550
551  static const size_t kHeaderSize = kWriteBarrierCounterOffset + kPointerSize +
552                                    kIntSize + kIntSize + kPointerSize +
553                                    5 * kPointerSize;
554
555  static const int kBodyOffset =
556      CODE_POINTER_ALIGN(kHeaderSize + Bitmap::kSize);
557
558  // The start offset of the object area in a page. Aligned to both maps and
559  // code alignment to be suitable for both.  Also aligned to 32 words because
560  // the marking bitmap is arranged in 32 bit chunks.
561  static const int kObjectStartAlignment = 32 * kPointerSize;
562  static const int kObjectStartOffset = kBodyOffset - 1 +
563      (kObjectStartAlignment - (kBodyOffset - 1) % kObjectStartAlignment);
564
565  size_t size() const { return size_; }
566
567  void set_size(size_t size) {
568    size_ = size;
569  }
570
571  void SetArea(Address area_start, Address area_end) {
572    area_start_ = area_start;
573    area_end_ = area_end;
574  }
575
576  Executability executable() {
577    return IsFlagSet(IS_EXECUTABLE) ? EXECUTABLE : NOT_EXECUTABLE;
578  }
579
580  bool ContainsOnlyData() {
581    return IsFlagSet(CONTAINS_ONLY_DATA);
582  }
583
584  bool InNewSpace() {
585    return (flags_ & ((1 << IN_FROM_SPACE) | (1 << IN_TO_SPACE))) != 0;
586  }
587
588  bool InToSpace() {
589    return IsFlagSet(IN_TO_SPACE);
590  }
591
592  bool InFromSpace() {
593    return IsFlagSet(IN_FROM_SPACE);
594  }
595
596  // ---------------------------------------------------------------------
597  // Markbits support
598
599  inline Bitmap* markbits() {
600    return Bitmap::FromAddress(address() + kHeaderSize);
601  }
602
603  void PrintMarkbits() { markbits()->Print(); }
604
605  inline uint32_t AddressToMarkbitIndex(Address addr) {
606    return static_cast<uint32_t>(addr - this->address()) >> kPointerSizeLog2;
607  }
608
609  inline static uint32_t FastAddressToMarkbitIndex(Address addr) {
610    const intptr_t offset =
611        reinterpret_cast<intptr_t>(addr) & kAlignmentMask;
612
613    return static_cast<uint32_t>(offset) >> kPointerSizeLog2;
614  }
615
616  inline Address MarkbitIndexToAddress(uint32_t index) {
617    return this->address() + (index << kPointerSizeLog2);
618  }
619
620  void InsertAfter(MemoryChunk* other);
621  void Unlink();
622
623  inline Heap* heap() { return heap_; }
624
625  static const int kFlagsOffset = kPointerSize * 3;
626
627  bool IsEvacuationCandidate() { return IsFlagSet(EVACUATION_CANDIDATE); }
628
629  bool ShouldSkipEvacuationSlotRecording() {
630    return (flags_ & kSkipEvacuationSlotsRecordingMask) != 0;
631  }
632
633  inline SkipList* skip_list() {
634    return skip_list_;
635  }
636
637  inline void set_skip_list(SkipList* skip_list) {
638    skip_list_ = skip_list;
639  }
640
641  inline SlotsBuffer* slots_buffer() {
642    return slots_buffer_;
643  }
644
645  inline SlotsBuffer** slots_buffer_address() {
646    return &slots_buffer_;
647  }
648
649  void MarkEvacuationCandidate() {
650    ASSERT(slots_buffer_ == NULL);
651    SetFlag(EVACUATION_CANDIDATE);
652  }
653
654  void ClearEvacuationCandidate() {
655    ASSERT(slots_buffer_ == NULL);
656    ClearFlag(EVACUATION_CANDIDATE);
657  }
658
659  Address area_start() { return area_start_; }
660  Address area_end() { return area_end_; }
661  int area_size() {
662    return static_cast<int>(area_end() - area_start());
663  }
664  bool CommitArea(size_t requested);
665
666  // Approximate amount of physical memory committed for this chunk.
667  size_t CommittedPhysicalMemory() {
668    return high_water_mark_;
669  }
670
671  static inline void UpdateHighWaterMark(Address mark);
672
673 protected:
674  MemoryChunk* next_chunk_;
675  MemoryChunk* prev_chunk_;
676  size_t size_;
677  intptr_t flags_;
678
679  // Start and end of allocatable memory on this chunk.
680  Address area_start_;
681  Address area_end_;
682
683  // If the chunk needs to remember its memory reservation, it is stored here.
684  VirtualMemory reservation_;
685  // The identity of the owning space.  This is tagged as a failure pointer, but
686  // no failure can be in an object, so this can be distinguished from any entry
687  // in a fixed array.
688  Address owner_;
689  Heap* heap_;
690  // Used by the store buffer to keep track of which pages to mark scan-on-
691  // scavenge.
692  int store_buffer_counter_;
693  // Count of bytes marked black on page.
694  int live_byte_count_;
695  SlotsBuffer* slots_buffer_;
696  SkipList* skip_list_;
697  intptr_t write_barrier_counter_;
698  // Used by the incremental marker to keep track of the scanning progress in
699  // large objects that have a progress bar and are scanned in increments.
700  int progress_bar_;
701  // Assuming the initial allocation on a page is sequential,
702  // count highest number of bytes ever allocated on the page.
703  int high_water_mark_;
704
705  intptr_t parallel_sweeping_;
706
707  // PagedSpace free-list statistics.
708  intptr_t available_in_small_free_list_;
709  intptr_t available_in_medium_free_list_;
710  intptr_t available_in_large_free_list_;
711  intptr_t available_in_huge_free_list_;
712  intptr_t non_available_small_blocks_;
713
714  static MemoryChunk* Initialize(Heap* heap,
715                                 Address base,
716                                 size_t size,
717                                 Address area_start,
718                                 Address area_end,
719                                 Executability executable,
720                                 Space* owner);
721
722  friend class MemoryAllocator;
723};
724
725
726STATIC_CHECK(sizeof(MemoryChunk) <= MemoryChunk::kHeaderSize);
727
728
729// -----------------------------------------------------------------------------
730// A page is a memory chunk of a size 1MB. Large object pages may be larger.
731//
732// The only way to get a page pointer is by calling factory methods:
733//   Page* p = Page::FromAddress(addr); or
734//   Page* p = Page::FromAllocationTop(top);
735class Page : public MemoryChunk {
736 public:
737  // Returns the page containing a given address. The address ranges
738  // from [page_addr .. page_addr + kPageSize[
739  // This only works if the object is in fact in a page.  See also MemoryChunk::
740  // FromAddress() and FromAnyAddress().
741  INLINE(static Page* FromAddress(Address a)) {
742    return reinterpret_cast<Page*>(OffsetFrom(a) & ~kPageAlignmentMask);
743  }
744
745  // Returns the page containing an allocation top. Because an allocation
746  // top address can be the upper bound of the page, we need to subtract
747  // it with kPointerSize first. The address ranges from
748  // [page_addr + kObjectStartOffset .. page_addr + kPageSize].
749  INLINE(static Page* FromAllocationTop(Address top)) {
750    Page* p = FromAddress(top - kPointerSize);
751    return p;
752  }
753
754  // Returns the next page in the chain of pages owned by a space.
755  inline Page* next_page();
756  inline Page* prev_page();
757  inline void set_next_page(Page* page);
758  inline void set_prev_page(Page* page);
759
760  // Checks whether an address is page aligned.
761  static bool IsAlignedToPageSize(Address a) {
762    return 0 == (OffsetFrom(a) & kPageAlignmentMask);
763  }
764
765  // Returns the offset of a given address to this page.
766  INLINE(int Offset(Address a)) {
767    int offset = static_cast<int>(a - address());
768    return offset;
769  }
770
771  // Returns the address for a given offset to the this page.
772  Address OffsetToAddress(int offset) {
773    ASSERT_PAGE_OFFSET(offset);
774    return address() + offset;
775  }
776
777  // ---------------------------------------------------------------------
778
779  // Page size in bytes.  This must be a multiple of the OS page size.
780  static const int kPageSize = 1 << kPageSizeBits;
781
782  // Object area size in bytes.
783  static const int kNonCodeObjectAreaSize = kPageSize - kObjectStartOffset;
784
785  // Maximum object size that fits in a page. Objects larger than that size are
786  // allocated in large object space and are never moved in memory. This also
787  // applies to new space allocation, since objects are never migrated from new
788  // space to large object space.  Takes double alignment into account.
789  static const int kMaxRegularHeapObjectSize = kPageSize - kObjectStartOffset;
790
791  // Maximum object size that fits in a page. Objects larger than that size
792  // are allocated in large object space and are never moved in memory. This
793  // also applies to new space allocation, since objects are never migrated
794  // from new space to large object space.  Takes double alignment into account.
795  static const int kMaxNonCodeHeapObjectSize =
796      kNonCodeObjectAreaSize - kPointerSize;
797
798  // Page size mask.
799  static const intptr_t kPageAlignmentMask = (1 << kPageSizeBits) - 1;
800
801  inline void ClearGCFields();
802
803  static inline Page* Initialize(Heap* heap,
804                                 MemoryChunk* chunk,
805                                 Executability executable,
806                                 PagedSpace* owner);
807
808  void InitializeAsAnchor(PagedSpace* owner);
809
810  bool WasSweptPrecisely() { return IsFlagSet(WAS_SWEPT_PRECISELY); }
811  bool WasSweptConservatively() { return IsFlagSet(WAS_SWEPT_CONSERVATIVELY); }
812  bool WasSwept() { return WasSweptPrecisely() || WasSweptConservatively(); }
813
814  void MarkSweptPrecisely() { SetFlag(WAS_SWEPT_PRECISELY); }
815  void MarkSweptConservatively() { SetFlag(WAS_SWEPT_CONSERVATIVELY); }
816
817  void ClearSweptPrecisely() { ClearFlag(WAS_SWEPT_PRECISELY); }
818  void ClearSweptConservatively() { ClearFlag(WAS_SWEPT_CONSERVATIVELY); }
819
820  void ResetFreeListStatistics();
821
822#define FRAGMENTATION_STATS_ACCESSORS(type, name) \
823  type name() { return name##_; }                 \
824  void set_##name(type name) { name##_ = name; }  \
825  void add_##name(type name) { name##_ += name; }
826
827  FRAGMENTATION_STATS_ACCESSORS(intptr_t, non_available_small_blocks)
828  FRAGMENTATION_STATS_ACCESSORS(intptr_t, available_in_small_free_list)
829  FRAGMENTATION_STATS_ACCESSORS(intptr_t, available_in_medium_free_list)
830  FRAGMENTATION_STATS_ACCESSORS(intptr_t, available_in_large_free_list)
831  FRAGMENTATION_STATS_ACCESSORS(intptr_t, available_in_huge_free_list)
832
833#undef FRAGMENTATION_STATS_ACCESSORS
834
835#ifdef DEBUG
836  void Print();
837#endif  // DEBUG
838
839  friend class MemoryAllocator;
840};
841
842
843STATIC_CHECK(sizeof(Page) <= MemoryChunk::kHeaderSize);
844
845
846class LargePage : public MemoryChunk {
847 public:
848  HeapObject* GetObject() {
849    return HeapObject::FromAddress(area_start());
850  }
851
852  inline LargePage* next_page() const {
853    return static_cast<LargePage*>(next_chunk());
854  }
855
856  inline void set_next_page(LargePage* page) {
857    set_next_chunk(page);
858  }
859 private:
860  static inline LargePage* Initialize(Heap* heap, MemoryChunk* chunk);
861
862  friend class MemoryAllocator;
863};
864
865STATIC_CHECK(sizeof(LargePage) <= MemoryChunk::kHeaderSize);
866
867// ----------------------------------------------------------------------------
868// Space is the abstract superclass for all allocation spaces.
869class Space : public Malloced {
870 public:
871  Space(Heap* heap, AllocationSpace id, Executability executable)
872      : heap_(heap), id_(id), executable_(executable) {}
873
874  virtual ~Space() {}
875
876  Heap* heap() const { return heap_; }
877
878  // Does the space need executable memory?
879  Executability executable() { return executable_; }
880
881  // Identity used in error reporting.
882  AllocationSpace identity() { return id_; }
883
884  // Returns allocated size.
885  virtual intptr_t Size() = 0;
886
887  // Returns size of objects. Can differ from the allocated size
888  // (e.g. see LargeObjectSpace).
889  virtual intptr_t SizeOfObjects() { return Size(); }
890
891  virtual int RoundSizeDownToObjectAlignment(int size) {
892    if (id_ == CODE_SPACE) {
893      return RoundDown(size, kCodeAlignment);
894    } else {
895      return RoundDown(size, kPointerSize);
896    }
897  }
898
899#ifdef DEBUG
900  virtual void Print() = 0;
901#endif
902
903 private:
904  Heap* heap_;
905  AllocationSpace id_;
906  Executability executable_;
907};
908
909
910// ----------------------------------------------------------------------------
911// All heap objects containing executable code (code objects) must be allocated
912// from a 2 GB range of memory, so that they can call each other using 32-bit
913// displacements.  This happens automatically on 32-bit platforms, where 32-bit
914// displacements cover the entire 4GB virtual address space.  On 64-bit
915// platforms, we support this using the CodeRange object, which reserves and
916// manages a range of virtual memory.
917class CodeRange {
918 public:
919  explicit CodeRange(Isolate* isolate);
920  ~CodeRange() { TearDown(); }
921
922  // Reserves a range of virtual memory, but does not commit any of it.
923  // Can only be called once, at heap initialization time.
924  // Returns false on failure.
925  bool SetUp(const size_t requested_size);
926
927  // Frees the range of virtual memory, and frees the data structures used to
928  // manage it.
929  void TearDown();
930
931  bool exists() { return this != NULL && code_range_ != NULL; }
932  Address start() {
933    if (this == NULL || code_range_ == NULL) return NULL;
934    return static_cast<Address>(code_range_->address());
935  }
936  bool contains(Address address) {
937    if (this == NULL || code_range_ == NULL) return false;
938    Address start = static_cast<Address>(code_range_->address());
939    return start <= address && address < start + code_range_->size();
940  }
941
942  // Allocates a chunk of memory from the large-object portion of
943  // the code range.  On platforms with no separate code range, should
944  // not be called.
945  MUST_USE_RESULT Address AllocateRawMemory(const size_t requested_size,
946                                            const size_t commit_size,
947                                            size_t* allocated);
948  bool CommitRawMemory(Address start, size_t length);
949  bool UncommitRawMemory(Address start, size_t length);
950  void FreeRawMemory(Address buf, size_t length);
951
952 private:
953  Isolate* isolate_;
954
955  // The reserved range of virtual memory that all code objects are put in.
956  VirtualMemory* code_range_;
957  // Plain old data class, just a struct plus a constructor.
958  class FreeBlock {
959   public:
960    FreeBlock(Address start_arg, size_t size_arg)
961        : start(start_arg), size(size_arg) {
962      ASSERT(IsAddressAligned(start, MemoryChunk::kAlignment));
963      ASSERT(size >= static_cast<size_t>(Page::kPageSize));
964    }
965    FreeBlock(void* start_arg, size_t size_arg)
966        : start(static_cast<Address>(start_arg)), size(size_arg) {
967      ASSERT(IsAddressAligned(start, MemoryChunk::kAlignment));
968      ASSERT(size >= static_cast<size_t>(Page::kPageSize));
969    }
970
971    Address start;
972    size_t size;
973  };
974
975  // Freed blocks of memory are added to the free list.  When the allocation
976  // list is exhausted, the free list is sorted and merged to make the new
977  // allocation list.
978  List<FreeBlock> free_list_;
979  // Memory is allocated from the free blocks on the allocation list.
980  // The block at current_allocation_block_index_ is the current block.
981  List<FreeBlock> allocation_list_;
982  int current_allocation_block_index_;
983
984  // Finds a block on the allocation list that contains at least the
985  // requested amount of memory.  If none is found, sorts and merges
986  // the existing free memory blocks, and searches again.
987  // If none can be found, terminates V8 with FatalProcessOutOfMemory.
988  void GetNextAllocationBlock(size_t requested);
989  // Compares the start addresses of two free blocks.
990  static int CompareFreeBlockAddress(const FreeBlock* left,
991                                     const FreeBlock* right);
992
993  DISALLOW_COPY_AND_ASSIGN(CodeRange);
994};
995
996
997class SkipList {
998 public:
999  SkipList() {
1000    Clear();
1001  }
1002
1003  void Clear() {
1004    for (int idx = 0; idx < kSize; idx++) {
1005      starts_[idx] = reinterpret_cast<Address>(-1);
1006    }
1007  }
1008
1009  Address StartFor(Address addr) {
1010    return starts_[RegionNumber(addr)];
1011  }
1012
1013  void AddObject(Address addr, int size) {
1014    int start_region = RegionNumber(addr);
1015    int end_region = RegionNumber(addr + size - kPointerSize);
1016    for (int idx = start_region; idx <= end_region; idx++) {
1017      if (starts_[idx] > addr) starts_[idx] = addr;
1018    }
1019  }
1020
1021  static inline int RegionNumber(Address addr) {
1022    return (OffsetFrom(addr) & Page::kPageAlignmentMask) >> kRegionSizeLog2;
1023  }
1024
1025  static void Update(Address addr, int size) {
1026    Page* page = Page::FromAddress(addr);
1027    SkipList* list = page->skip_list();
1028    if (list == NULL) {
1029      list = new SkipList();
1030      page->set_skip_list(list);
1031    }
1032
1033    list->AddObject(addr, size);
1034  }
1035
1036 private:
1037  static const int kRegionSizeLog2 = 13;
1038  static const int kRegionSize = 1 << kRegionSizeLog2;
1039  static const int kSize = Page::kPageSize / kRegionSize;
1040
1041  STATIC_ASSERT(Page::kPageSize % kRegionSize == 0);
1042
1043  Address starts_[kSize];
1044};
1045
1046
1047// ----------------------------------------------------------------------------
1048// A space acquires chunks of memory from the operating system. The memory
1049// allocator allocated and deallocates pages for the paged heap spaces and large
1050// pages for large object space.
1051//
1052// Each space has to manage it's own pages.
1053//
1054class MemoryAllocator {
1055 public:
1056  explicit MemoryAllocator(Isolate* isolate);
1057
1058  // Initializes its internal bookkeeping structures.
1059  // Max capacity of the total space and executable memory limit.
1060  bool SetUp(intptr_t max_capacity, intptr_t capacity_executable);
1061
1062  void TearDown();
1063
1064  Page* AllocatePage(
1065      intptr_t size, PagedSpace* owner, Executability executable);
1066
1067  LargePage* AllocateLargePage(
1068      intptr_t object_size, Space* owner, Executability executable);
1069
1070  void Free(MemoryChunk* chunk);
1071
1072  // Returns the maximum available bytes of heaps.
1073  intptr_t Available() { return capacity_ < size_ ? 0 : capacity_ - size_; }
1074
1075  // Returns allocated spaces in bytes.
1076  intptr_t Size() { return size_; }
1077
1078  // Returns the maximum available executable bytes of heaps.
1079  intptr_t AvailableExecutable() {
1080    if (capacity_executable_ < size_executable_) return 0;
1081    return capacity_executable_ - size_executable_;
1082  }
1083
1084  // Returns allocated executable spaces in bytes.
1085  intptr_t SizeExecutable() { return size_executable_; }
1086
1087  // Returns maximum available bytes that the old space can have.
1088  intptr_t MaxAvailable() {
1089    return (Available() / Page::kPageSize) * Page::kMaxNonCodeHeapObjectSize;
1090  }
1091
1092  // Returns an indication of whether a pointer is in a space that has
1093  // been allocated by this MemoryAllocator.
1094  V8_INLINE bool IsOutsideAllocatedSpace(const void* address) const {
1095    return address < lowest_ever_allocated_ ||
1096        address >= highest_ever_allocated_;
1097  }
1098
1099#ifdef DEBUG
1100  // Reports statistic info of the space.
1101  void ReportStatistics();
1102#endif
1103
1104  // Returns a MemoryChunk in which the memory region from commit_area_size to
1105  // reserve_area_size of the chunk area is reserved but not committed, it
1106  // could be committed later by calling MemoryChunk::CommitArea.
1107  MemoryChunk* AllocateChunk(intptr_t reserve_area_size,
1108                             intptr_t commit_area_size,
1109                             Executability executable,
1110                             Space* space);
1111
1112  Address ReserveAlignedMemory(size_t requested,
1113                               size_t alignment,
1114                               VirtualMemory* controller);
1115  Address AllocateAlignedMemory(size_t reserve_size,
1116                                size_t commit_size,
1117                                size_t alignment,
1118                                Executability executable,
1119                                VirtualMemory* controller);
1120
1121  bool CommitMemory(Address addr, size_t size, Executability executable);
1122
1123  void FreeMemory(VirtualMemory* reservation, Executability executable);
1124  void FreeMemory(Address addr, size_t size, Executability executable);
1125
1126  // Commit a contiguous block of memory from the initial chunk.  Assumes that
1127  // the address is not NULL, the size is greater than zero, and that the
1128  // block is contained in the initial chunk.  Returns true if it succeeded
1129  // and false otherwise.
1130  bool CommitBlock(Address start, size_t size, Executability executable);
1131
1132  // Uncommit a contiguous block of memory [start..(start+size)[.
1133  // start is not NULL, the size is greater than zero, and the
1134  // block is contained in the initial chunk.  Returns true if it succeeded
1135  // and false otherwise.
1136  bool UncommitBlock(Address start, size_t size);
1137
1138  // Zaps a contiguous block of memory [start..(start+size)[ thus
1139  // filling it up with a recognizable non-NULL bit pattern.
1140  void ZapBlock(Address start, size_t size);
1141
1142  void PerformAllocationCallback(ObjectSpace space,
1143                                 AllocationAction action,
1144                                 size_t size);
1145
1146  void AddMemoryAllocationCallback(MemoryAllocationCallback callback,
1147                                          ObjectSpace space,
1148                                          AllocationAction action);
1149
1150  void RemoveMemoryAllocationCallback(
1151      MemoryAllocationCallback callback);
1152
1153  bool MemoryAllocationCallbackRegistered(
1154      MemoryAllocationCallback callback);
1155
1156  static int CodePageGuardStartOffset();
1157
1158  static int CodePageGuardSize();
1159
1160  static int CodePageAreaStartOffset();
1161
1162  static int CodePageAreaEndOffset();
1163
1164  static int CodePageAreaSize() {
1165    return CodePageAreaEndOffset() - CodePageAreaStartOffset();
1166  }
1167
1168  MUST_USE_RESULT bool CommitExecutableMemory(VirtualMemory* vm,
1169                                              Address start,
1170                                              size_t commit_size,
1171                                              size_t reserved_size);
1172
1173 private:
1174  Isolate* isolate_;
1175
1176  // Maximum space size in bytes.
1177  size_t capacity_;
1178  // Maximum subset of capacity_ that can be executable
1179  size_t capacity_executable_;
1180
1181  // Allocated space size in bytes.
1182  size_t size_;
1183  // Allocated executable space size in bytes.
1184  size_t size_executable_;
1185
1186  // We keep the lowest and highest addresses allocated as a quick way
1187  // of determining that pointers are outside the heap. The estimate is
1188  // conservative, i.e. not all addrsses in 'allocated' space are allocated
1189  // to our heap. The range is [lowest, highest[, inclusive on the low end
1190  // and exclusive on the high end.
1191  void* lowest_ever_allocated_;
1192  void* highest_ever_allocated_;
1193
1194  struct MemoryAllocationCallbackRegistration {
1195    MemoryAllocationCallbackRegistration(MemoryAllocationCallback callback,
1196                                         ObjectSpace space,
1197                                         AllocationAction action)
1198        : callback(callback), space(space), action(action) {
1199    }
1200    MemoryAllocationCallback callback;
1201    ObjectSpace space;
1202    AllocationAction action;
1203  };
1204
1205  // A List of callback that are triggered when memory is allocated or free'd
1206  List<MemoryAllocationCallbackRegistration>
1207      memory_allocation_callbacks_;
1208
1209  // Initializes pages in a chunk. Returns the first page address.
1210  // This function and GetChunkId() are provided for the mark-compact
1211  // collector to rebuild page headers in the from space, which is
1212  // used as a marking stack and its page headers are destroyed.
1213  Page* InitializePagesInChunk(int chunk_id, int pages_in_chunk,
1214                               PagedSpace* owner);
1215
1216  void UpdateAllocatedSpaceLimits(void* low, void* high) {
1217    lowest_ever_allocated_ = Min(lowest_ever_allocated_, low);
1218    highest_ever_allocated_ = Max(highest_ever_allocated_, high);
1219  }
1220
1221  DISALLOW_IMPLICIT_CONSTRUCTORS(MemoryAllocator);
1222};
1223
1224
1225// -----------------------------------------------------------------------------
1226// Interface for heap object iterator to be implemented by all object space
1227// object iterators.
1228//
1229// NOTE: The space specific object iterators also implements the own next()
1230//       method which is used to avoid using virtual functions
1231//       iterating a specific space.
1232
1233class ObjectIterator : public Malloced {
1234 public:
1235  virtual ~ObjectIterator() { }
1236
1237  virtual HeapObject* next_object() = 0;
1238};
1239
1240
1241// -----------------------------------------------------------------------------
1242// Heap object iterator in new/old/map spaces.
1243//
1244// A HeapObjectIterator iterates objects from the bottom of the given space
1245// to its top or from the bottom of the given page to its top.
1246//
1247// If objects are allocated in the page during iteration the iterator may
1248// or may not iterate over those objects.  The caller must create a new
1249// iterator in order to be sure to visit these new objects.
1250class HeapObjectIterator: public ObjectIterator {
1251 public:
1252  // Creates a new object iterator in a given space.
1253  // If the size function is not given, the iterator calls the default
1254  // Object::Size().
1255  explicit HeapObjectIterator(PagedSpace* space);
1256  HeapObjectIterator(PagedSpace* space, HeapObjectCallback size_func);
1257  HeapObjectIterator(Page* page, HeapObjectCallback size_func);
1258
1259  // Advance to the next object, skipping free spaces and other fillers and
1260  // skipping the special garbage section of which there is one per space.
1261  // Returns NULL when the iteration has ended.
1262  inline HeapObject* Next() {
1263    do {
1264      HeapObject* next_obj = FromCurrentPage();
1265      if (next_obj != NULL) return next_obj;
1266    } while (AdvanceToNextPage());
1267    return NULL;
1268  }
1269
1270  virtual HeapObject* next_object() {
1271    return Next();
1272  }
1273
1274 private:
1275  enum PageMode { kOnePageOnly, kAllPagesInSpace };
1276
1277  Address cur_addr_;  // Current iteration point.
1278  Address cur_end_;   // End iteration point.
1279  HeapObjectCallback size_func_;  // Size function or NULL.
1280  PagedSpace* space_;
1281  PageMode page_mode_;
1282
1283  // Fast (inlined) path of next().
1284  inline HeapObject* FromCurrentPage();
1285
1286  // Slow path of next(), goes into the next page.  Returns false if the
1287  // iteration has ended.
1288  bool AdvanceToNextPage();
1289
1290  // Initializes fields.
1291  inline void Initialize(PagedSpace* owner,
1292                         Address start,
1293                         Address end,
1294                         PageMode mode,
1295                         HeapObjectCallback size_func);
1296};
1297
1298
1299// -----------------------------------------------------------------------------
1300// A PageIterator iterates the pages in a paged space.
1301
1302class PageIterator BASE_EMBEDDED {
1303 public:
1304  explicit inline PageIterator(PagedSpace* space);
1305
1306  inline bool has_next();
1307  inline Page* next();
1308
1309 private:
1310  PagedSpace* space_;
1311  Page* prev_page_;  // Previous page returned.
1312  // Next page that will be returned.  Cached here so that we can use this
1313  // iterator for operations that deallocate pages.
1314  Page* next_page_;
1315};
1316
1317
1318// -----------------------------------------------------------------------------
1319// A space has a circular list of pages. The next page can be accessed via
1320// Page::next_page() call.
1321
1322// An abstraction of allocation and relocation pointers in a page-structured
1323// space.
1324class AllocationInfo {
1325 public:
1326  AllocationInfo() : top_(NULL), limit_(NULL) {
1327  }
1328
1329  INLINE(void set_top(Address top)) {
1330    SLOW_ASSERT(top == NULL ||
1331        (reinterpret_cast<intptr_t>(top) & HeapObjectTagMask()) == 0);
1332    top_ = top;
1333  }
1334
1335  INLINE(Address top()) const {
1336    SLOW_ASSERT(top_ == NULL ||
1337        (reinterpret_cast<intptr_t>(top_) & HeapObjectTagMask()) == 0);
1338    return top_;
1339  }
1340
1341  Address* top_address() {
1342    return &top_;
1343  }
1344
1345  INLINE(void set_limit(Address limit)) {
1346    SLOW_ASSERT(limit == NULL ||
1347        (reinterpret_cast<intptr_t>(limit) & HeapObjectTagMask()) == 0);
1348    limit_ = limit;
1349  }
1350
1351  INLINE(Address limit()) const {
1352    SLOW_ASSERT(limit_ == NULL ||
1353        (reinterpret_cast<intptr_t>(limit_) & HeapObjectTagMask()) == 0);
1354    return limit_;
1355  }
1356
1357  Address* limit_address() {
1358    return &limit_;
1359  }
1360
1361#ifdef DEBUG
1362  bool VerifyPagedAllocation() {
1363    return (Page::FromAllocationTop(top_) == Page::FromAllocationTop(limit_))
1364        && (top_ <= limit_);
1365  }
1366#endif
1367
1368 private:
1369  // Current allocation top.
1370  Address top_;
1371  // Current allocation limit.
1372  Address limit_;
1373};
1374
1375
1376// An abstraction of the accounting statistics of a page-structured space.
1377// The 'capacity' of a space is the number of object-area bytes (i.e., not
1378// including page bookkeeping structures) currently in the space. The 'size'
1379// of a space is the number of allocated bytes, the 'waste' in the space is
1380// the number of bytes that are not allocated and not available to
1381// allocation without reorganizing the space via a GC (e.g. small blocks due
1382// to internal fragmentation, top of page areas in map space), and the bytes
1383// 'available' is the number of unallocated bytes that are not waste.  The
1384// capacity is the sum of size, waste, and available.
1385//
1386// The stats are only set by functions that ensure they stay balanced. These
1387// functions increase or decrease one of the non-capacity stats in
1388// conjunction with capacity, or else they always balance increases and
1389// decreases to the non-capacity stats.
1390class AllocationStats BASE_EMBEDDED {
1391 public:
1392  AllocationStats() { Clear(); }
1393
1394  // Zero out all the allocation statistics (i.e., no capacity).
1395  void Clear() {
1396    capacity_ = 0;
1397    max_capacity_ = 0;
1398    size_ = 0;
1399    waste_ = 0;
1400  }
1401
1402  void ClearSizeWaste() {
1403    size_ = capacity_;
1404    waste_ = 0;
1405  }
1406
1407  // Reset the allocation statistics (i.e., available = capacity with no
1408  // wasted or allocated bytes).
1409  void Reset() {
1410    size_ = 0;
1411    waste_ = 0;
1412  }
1413
1414  // Accessors for the allocation statistics.
1415  intptr_t Capacity() { return capacity_; }
1416  intptr_t MaxCapacity() { return max_capacity_; }
1417  intptr_t Size() { return size_; }
1418  intptr_t Waste() { return waste_; }
1419
1420  // Grow the space by adding available bytes.  They are initially marked as
1421  // being in use (part of the size), but will normally be immediately freed,
1422  // putting them on the free list and removing them from size_.
1423  void ExpandSpace(int size_in_bytes) {
1424    capacity_ += size_in_bytes;
1425    size_ += size_in_bytes;
1426    if (capacity_ > max_capacity_) {
1427      max_capacity_ = capacity_;
1428    }
1429    ASSERT(size_ >= 0);
1430  }
1431
1432  // Shrink the space by removing available bytes.  Since shrinking is done
1433  // during sweeping, bytes have been marked as being in use (part of the size)
1434  // and are hereby freed.
1435  void ShrinkSpace(int size_in_bytes) {
1436    capacity_ -= size_in_bytes;
1437    size_ -= size_in_bytes;
1438    ASSERT(size_ >= 0);
1439  }
1440
1441  // Allocate from available bytes (available -> size).
1442  void AllocateBytes(intptr_t size_in_bytes) {
1443    size_ += size_in_bytes;
1444    ASSERT(size_ >= 0);
1445  }
1446
1447  // Free allocated bytes, making them available (size -> available).
1448  void DeallocateBytes(intptr_t size_in_bytes) {
1449    size_ -= size_in_bytes;
1450    ASSERT(size_ >= 0);
1451  }
1452
1453  // Waste free bytes (available -> waste).
1454  void WasteBytes(int size_in_bytes) {
1455    size_ -= size_in_bytes;
1456    waste_ += size_in_bytes;
1457    ASSERT(size_ >= 0);
1458  }
1459
1460 private:
1461  intptr_t capacity_;
1462  intptr_t max_capacity_;
1463  intptr_t size_;
1464  intptr_t waste_;
1465};
1466
1467
1468// -----------------------------------------------------------------------------
1469// Free lists for old object spaces
1470//
1471// Free-list nodes are free blocks in the heap.  They look like heap objects
1472// (free-list node pointers have the heap object tag, and they have a map like
1473// a heap object).  They have a size and a next pointer.  The next pointer is
1474// the raw address of the next free list node (or NULL).
1475class FreeListNode: public HeapObject {
1476 public:
1477  // Obtain a free-list node from a raw address.  This is not a cast because
1478  // it does not check nor require that the first word at the address is a map
1479  // pointer.
1480  static FreeListNode* FromAddress(Address address) {
1481    return reinterpret_cast<FreeListNode*>(HeapObject::FromAddress(address));
1482  }
1483
1484  static inline bool IsFreeListNode(HeapObject* object);
1485
1486  // Set the size in bytes, which can be read with HeapObject::Size().  This
1487  // function also writes a map to the first word of the block so that it
1488  // looks like a heap object to the garbage collector and heap iteration
1489  // functions.
1490  void set_size(Heap* heap, int size_in_bytes);
1491
1492  // Accessors for the next field.
1493  inline FreeListNode* next();
1494  inline FreeListNode** next_address();
1495  inline void set_next(FreeListNode* next);
1496
1497  inline void Zap();
1498
1499  static inline FreeListNode* cast(MaybeObject* maybe) {
1500    ASSERT(!maybe->IsFailure());
1501    return reinterpret_cast<FreeListNode*>(maybe);
1502  }
1503
1504 private:
1505  static const int kNextOffset = POINTER_SIZE_ALIGN(FreeSpace::kHeaderSize);
1506
1507  DISALLOW_IMPLICIT_CONSTRUCTORS(FreeListNode);
1508};
1509
1510
1511// The free list category holds a pointer to the top element and a pointer to
1512// the end element of the linked list of free memory blocks.
1513class FreeListCategory {
1514 public:
1515  FreeListCategory() :
1516      top_(NULL),
1517      end_(NULL),
1518      available_(0) {}
1519
1520  intptr_t Concatenate(FreeListCategory* category);
1521
1522  void Reset();
1523
1524  void Free(FreeListNode* node, int size_in_bytes);
1525
1526  FreeListNode* PickNodeFromList(int *node_size);
1527  FreeListNode* PickNodeFromList(int size_in_bytes, int *node_size);
1528
1529  intptr_t EvictFreeListItemsInList(Page* p);
1530
1531  void RepairFreeList(Heap* heap);
1532
1533  FreeListNode** GetTopAddress() { return &top_; }
1534  FreeListNode* top() const { return top_; }
1535  void set_top(FreeListNode* top) { top_ = top; }
1536
1537  FreeListNode** GetEndAddress() { return &end_; }
1538  FreeListNode* end() const { return end_; }
1539  void set_end(FreeListNode* end) { end_ = end; }
1540
1541  int* GetAvailableAddress() { return &available_; }
1542  int available() const { return available_; }
1543  void set_available(int available) { available_ = available; }
1544
1545  Mutex* mutex() { return &mutex_; }
1546
1547#ifdef DEBUG
1548  intptr_t SumFreeList();
1549  int FreeListLength();
1550#endif
1551
1552 private:
1553  FreeListNode* top_;
1554  FreeListNode* end_;
1555  Mutex mutex_;
1556
1557  // Total available bytes in all blocks of this free list category.
1558  int available_;
1559};
1560
1561
1562// The free list for the old space.  The free list is organized in such a way
1563// as to encourage objects allocated around the same time to be near each
1564// other.  The normal way to allocate is intended to be by bumping a 'top'
1565// pointer until it hits a 'limit' pointer.  When the limit is hit we need to
1566// find a new space to allocate from.  This is done with the free list, which
1567// is divided up into rough categories to cut down on waste.  Having finer
1568// categories would scatter allocation more.
1569
1570// The old space free list is organized in categories.
1571// 1-31 words:  Such small free areas are discarded for efficiency reasons.
1572//     They can be reclaimed by the compactor.  However the distance between top
1573//     and limit may be this small.
1574// 32-255 words: There is a list of spaces this large.  It is used for top and
1575//     limit when the object we need to allocate is 1-31 words in size.  These
1576//     spaces are called small.
1577// 256-2047 words: There is a list of spaces this large.  It is used for top and
1578//     limit when the object we need to allocate is 32-255 words in size.  These
1579//     spaces are called medium.
1580// 1048-16383 words: There is a list of spaces this large.  It is used for top
1581//     and limit when the object we need to allocate is 256-2047 words in size.
1582//     These spaces are call large.
1583// At least 16384 words.  This list is for objects of 2048 words or larger.
1584//     Empty pages are added to this list.  These spaces are called huge.
1585class FreeList BASE_EMBEDDED {
1586 public:
1587  explicit FreeList(PagedSpace* owner);
1588
1589  intptr_t Concatenate(FreeList* free_list);
1590
1591  // Clear the free list.
1592  void Reset();
1593
1594  // Return the number of bytes available on the free list.
1595  intptr_t available() {
1596    return small_list_.available() + medium_list_.available() +
1597           large_list_.available() + huge_list_.available();
1598  }
1599
1600  // Place a node on the free list.  The block of size 'size_in_bytes'
1601  // starting at 'start' is placed on the free list.  The return value is the
1602  // number of bytes that have been lost due to internal fragmentation by
1603  // freeing the block.  Bookkeeping information will be written to the block,
1604  // i.e., its contents will be destroyed.  The start address should be word
1605  // aligned, and the size should be a non-zero multiple of the word size.
1606  int Free(Address start, int size_in_bytes);
1607
1608  // Allocate a block of size 'size_in_bytes' from the free list.  The block
1609  // is unitialized.  A failure is returned if no block is available.  The
1610  // number of bytes lost to fragmentation is returned in the output parameter
1611  // 'wasted_bytes'.  The size should be a non-zero multiple of the word size.
1612  MUST_USE_RESULT HeapObject* Allocate(int size_in_bytes);
1613
1614#ifdef DEBUG
1615  void Zap();
1616  intptr_t SumFreeLists();
1617  bool IsVeryLong();
1618#endif
1619
1620  // Used after booting the VM.
1621  void RepairLists(Heap* heap);
1622
1623  intptr_t EvictFreeListItems(Page* p);
1624
1625  FreeListCategory* small_list() { return &small_list_; }
1626  FreeListCategory* medium_list() { return &medium_list_; }
1627  FreeListCategory* large_list() { return &large_list_; }
1628  FreeListCategory* huge_list() { return &huge_list_; }
1629
1630 private:
1631  // The size range of blocks, in bytes.
1632  static const int kMinBlockSize = 3 * kPointerSize;
1633  static const int kMaxBlockSize = Page::kMaxNonCodeHeapObjectSize;
1634
1635  FreeListNode* FindNodeFor(int size_in_bytes, int* node_size);
1636
1637  PagedSpace* owner_;
1638  Heap* heap_;
1639
1640  static const int kSmallListMin = 0x20 * kPointerSize;
1641  static const int kSmallListMax = 0xff * kPointerSize;
1642  static const int kMediumListMax = 0x7ff * kPointerSize;
1643  static const int kLargeListMax = 0x3fff * kPointerSize;
1644  static const int kSmallAllocationMax = kSmallListMin - kPointerSize;
1645  static const int kMediumAllocationMax = kSmallListMax;
1646  static const int kLargeAllocationMax = kMediumListMax;
1647  FreeListCategory small_list_;
1648  FreeListCategory medium_list_;
1649  FreeListCategory large_list_;
1650  FreeListCategory huge_list_;
1651
1652  DISALLOW_IMPLICIT_CONSTRUCTORS(FreeList);
1653};
1654
1655
1656class PagedSpace : public Space {
1657 public:
1658  // Creates a space with a maximum capacity, and an id.
1659  PagedSpace(Heap* heap,
1660             intptr_t max_capacity,
1661             AllocationSpace id,
1662             Executability executable);
1663
1664  virtual ~PagedSpace() {}
1665
1666  // Set up the space using the given address range of virtual memory (from
1667  // the memory allocator's initial chunk) if possible.  If the block of
1668  // addresses is not big enough to contain a single page-aligned page, a
1669  // fresh chunk will be allocated.
1670  bool SetUp();
1671
1672  // Returns true if the space has been successfully set up and not
1673  // subsequently torn down.
1674  bool HasBeenSetUp();
1675
1676  // Cleans up the space, frees all pages in this space except those belonging
1677  // to the initial chunk, uncommits addresses in the initial chunk.
1678  void TearDown();
1679
1680  // Checks whether an object/address is in this space.
1681  inline bool Contains(Address a);
1682  bool Contains(HeapObject* o) { return Contains(o->address()); }
1683
1684  // Given an address occupied by a live object, return that object if it is
1685  // in this space, or Failure::Exception() if it is not. The implementation
1686  // iterates over objects in the page containing the address, the cost is
1687  // linear in the number of objects in the page. It may be slow.
1688  MUST_USE_RESULT MaybeObject* FindObject(Address addr);
1689
1690  // During boot the free_space_map is created, and afterwards we may need
1691  // to write it into the free list nodes that were already created.
1692  void RepairFreeListsAfterBoot();
1693
1694  // Prepares for a mark-compact GC.
1695  void PrepareForMarkCompact();
1696
1697  // Current capacity without growing (Size() + Available()).
1698  intptr_t Capacity() { return accounting_stats_.Capacity(); }
1699
1700  // Total amount of memory committed for this space.  For paged
1701  // spaces this equals the capacity.
1702  intptr_t CommittedMemory() { return Capacity(); }
1703
1704  // The maximum amount of memory ever committed for this space.
1705  intptr_t MaximumCommittedMemory() { return accounting_stats_.MaxCapacity(); }
1706
1707  // Approximate amount of physical memory committed for this space.
1708  size_t CommittedPhysicalMemory();
1709
1710  struct SizeStats {
1711    intptr_t Total() {
1712      return small_size_ + medium_size_ + large_size_ + huge_size_;
1713    }
1714
1715    intptr_t small_size_;
1716    intptr_t medium_size_;
1717    intptr_t large_size_;
1718    intptr_t huge_size_;
1719  };
1720
1721  void ObtainFreeListStatistics(Page* p, SizeStats* sizes);
1722  void ResetFreeListStatistics();
1723
1724  // Sets the capacity, the available space and the wasted space to zero.
1725  // The stats are rebuilt during sweeping by adding each page to the
1726  // capacity and the size when it is encountered.  As free spaces are
1727  // discovered during the sweeping they are subtracted from the size and added
1728  // to the available and wasted totals.
1729  void ClearStats() {
1730    accounting_stats_.ClearSizeWaste();
1731    ResetFreeListStatistics();
1732  }
1733
1734  // Increases the number of available bytes of that space.
1735  void AddToAccountingStats(intptr_t bytes) {
1736    accounting_stats_.DeallocateBytes(bytes);
1737  }
1738
1739  // Available bytes without growing.  These are the bytes on the free list.
1740  // The bytes in the linear allocation area are not included in this total
1741  // because updating the stats would slow down allocation.  New pages are
1742  // immediately added to the free list so they show up here.
1743  intptr_t Available() { return free_list_.available(); }
1744
1745  // Allocated bytes in this space.  Garbage bytes that were not found due to
1746  // lazy sweeping are counted as being allocated!  The bytes in the current
1747  // linear allocation area (between top and limit) are also counted here.
1748  virtual intptr_t Size() { return accounting_stats_.Size(); }
1749
1750  // As size, but the bytes in lazily swept pages are estimated and the bytes
1751  // in the current linear allocation area are not included.
1752  virtual intptr_t SizeOfObjects();
1753
1754  // Wasted bytes in this space.  These are just the bytes that were thrown away
1755  // due to being too small to use for allocation.  They do not include the
1756  // free bytes that were not found at all due to lazy sweeping.
1757  virtual intptr_t Waste() { return accounting_stats_.Waste(); }
1758
1759  // Returns the allocation pointer in this space.
1760  Address top() { return allocation_info_.top(); }
1761  Address limit() { return allocation_info_.limit(); }
1762
1763  // The allocation top address.
1764  Address* allocation_top_address() {
1765    return allocation_info_.top_address();
1766  }
1767
1768  // The allocation limit address.
1769  Address* allocation_limit_address() {
1770    return allocation_info_.limit_address();
1771  }
1772
1773  // Allocate the requested number of bytes in the space if possible, return a
1774  // failure object if not.
1775  MUST_USE_RESULT inline MaybeObject* AllocateRaw(int size_in_bytes);
1776
1777  // Give a block of memory to the space's free list.  It might be added to
1778  // the free list or accounted as waste.
1779  // If add_to_freelist is false then just accounting stats are updated and
1780  // no attempt to add area to free list is made.
1781  int Free(Address start, int size_in_bytes) {
1782    int wasted = free_list_.Free(start, size_in_bytes);
1783    accounting_stats_.DeallocateBytes(size_in_bytes - wasted);
1784    return size_in_bytes - wasted;
1785  }
1786
1787  void ResetFreeList() {
1788    free_list_.Reset();
1789  }
1790
1791  // Set space allocation info.
1792  void SetTopAndLimit(Address top, Address limit) {
1793    ASSERT(top == limit ||
1794           Page::FromAddress(top) == Page::FromAddress(limit - 1));
1795    MemoryChunk::UpdateHighWaterMark(allocation_info_.top());
1796    allocation_info_.set_top(top);
1797    allocation_info_.set_limit(limit);
1798  }
1799
1800  // Empty space allocation info, returning unused area to free list.
1801  void EmptyAllocationInfo() {
1802    // Mark the old linear allocation area with a free space map so it can be
1803    // skipped when scanning the heap.
1804    int old_linear_size = static_cast<int>(limit() - top());
1805    Free(top(), old_linear_size);
1806    SetTopAndLimit(NULL, NULL);
1807  }
1808
1809  void Allocate(int bytes) {
1810    accounting_stats_.AllocateBytes(bytes);
1811  }
1812
1813  void IncreaseCapacity(int size);
1814
1815  // Releases an unused page and shrinks the space.
1816  void ReleasePage(Page* page, bool unlink);
1817
1818  // The dummy page that anchors the linked list of pages.
1819  Page* anchor() { return &anchor_; }
1820
1821#ifdef VERIFY_HEAP
1822  // Verify integrity of this space.
1823  virtual void Verify(ObjectVisitor* visitor);
1824
1825  // Overridden by subclasses to verify space-specific object
1826  // properties (e.g., only maps or free-list nodes are in map space).
1827  virtual void VerifyObject(HeapObject* obj) {}
1828#endif
1829
1830#ifdef DEBUG
1831  // Print meta info and objects in this space.
1832  virtual void Print();
1833
1834  // Reports statistics for the space
1835  void ReportStatistics();
1836
1837  // Report code object related statistics
1838  void CollectCodeStatistics();
1839  static void ReportCodeStatistics(Isolate* isolate);
1840  static void ResetCodeStatistics(Isolate* isolate);
1841#endif
1842
1843  bool was_swept_conservatively() { return was_swept_conservatively_; }
1844  void set_was_swept_conservatively(bool b) { was_swept_conservatively_ = b; }
1845
1846  // Evacuation candidates are swept by evacuator.  Needs to return a valid
1847  // result before _and_ after evacuation has finished.
1848  static bool ShouldBeSweptLazily(Page* p) {
1849    return !p->IsEvacuationCandidate() &&
1850           !p->IsFlagSet(Page::RESCAN_ON_EVACUATION) &&
1851           !p->WasSweptPrecisely();
1852  }
1853
1854  void SetPagesToSweep(Page* first) {
1855    ASSERT(unswept_free_bytes_ == 0);
1856    if (first == &anchor_) first = NULL;
1857    first_unswept_page_ = first;
1858  }
1859
1860  void IncrementUnsweptFreeBytes(intptr_t by) {
1861    unswept_free_bytes_ += by;
1862  }
1863
1864  void IncreaseUnsweptFreeBytes(Page* p) {
1865    ASSERT(ShouldBeSweptLazily(p));
1866    unswept_free_bytes_ += (p->area_size() - p->LiveBytes());
1867  }
1868
1869  void DecrementUnsweptFreeBytes(intptr_t by) {
1870    unswept_free_bytes_ -= by;
1871  }
1872
1873  void DecreaseUnsweptFreeBytes(Page* p) {
1874    ASSERT(ShouldBeSweptLazily(p));
1875    unswept_free_bytes_ -= (p->area_size() - p->LiveBytes());
1876  }
1877
1878  void ResetUnsweptFreeBytes() {
1879    unswept_free_bytes_ = 0;
1880  }
1881
1882  bool AdvanceSweeper(intptr_t bytes_to_sweep);
1883
1884  // When parallel sweeper threads are active and the main thread finished
1885  // its sweeping phase, this function waits for them to complete, otherwise
1886  // AdvanceSweeper with size_in_bytes is called.
1887  bool EnsureSweeperProgress(intptr_t size_in_bytes);
1888
1889  bool IsLazySweepingComplete() {
1890    return !first_unswept_page_->is_valid();
1891  }
1892
1893  Page* FirstPage() { return anchor_.next_page(); }
1894  Page* LastPage() { return anchor_.prev_page(); }
1895
1896  void EvictEvacuationCandidatesFromFreeLists();
1897
1898  bool CanExpand();
1899
1900  // Returns the number of total pages in this space.
1901  int CountTotalPages();
1902
1903  // Return size of allocatable area on a page in this space.
1904  inline int AreaSize() {
1905    return area_size_;
1906  }
1907
1908 protected:
1909  FreeList* free_list() { return &free_list_; }
1910
1911  int area_size_;
1912
1913  // Maximum capacity of this space.
1914  intptr_t max_capacity_;
1915
1916  intptr_t SizeOfFirstPage();
1917
1918  // Accounting information for this space.
1919  AllocationStats accounting_stats_;
1920
1921  // The dummy page that anchors the double linked list of pages.
1922  Page anchor_;
1923
1924  // The space's free list.
1925  FreeList free_list_;
1926
1927  // Normal allocation information.
1928  AllocationInfo allocation_info_;
1929
1930  bool was_swept_conservatively_;
1931
1932  // The first page to be swept when the lazy sweeper advances. Is set
1933  // to NULL when all pages have been swept.
1934  Page* first_unswept_page_;
1935
1936  // The number of free bytes which could be reclaimed by advancing the
1937  // lazy sweeper.  This is only an estimation because lazy sweeping is
1938  // done conservatively.
1939  intptr_t unswept_free_bytes_;
1940
1941  // Expands the space by allocating a fixed number of pages. Returns false if
1942  // it cannot allocate requested number of pages from OS, or if the hard heap
1943  // size limit has been hit.
1944  bool Expand();
1945
1946  // Generic fast case allocation function that tries linear allocation at the
1947  // address denoted by top in allocation_info_.
1948  inline HeapObject* AllocateLinearly(int size_in_bytes);
1949
1950  // Slow path of AllocateRaw.  This function is space-dependent.
1951  MUST_USE_RESULT virtual HeapObject* SlowAllocateRaw(int size_in_bytes);
1952
1953  friend class PageIterator;
1954  friend class SweeperThread;
1955};
1956
1957
1958class NumberAndSizeInfo BASE_EMBEDDED {
1959 public:
1960  NumberAndSizeInfo() : number_(0), bytes_(0) {}
1961
1962  int number() const { return number_; }
1963  void increment_number(int num) { number_ += num; }
1964
1965  int bytes() const { return bytes_; }
1966  void increment_bytes(int size) { bytes_ += size; }
1967
1968  void clear() {
1969    number_ = 0;
1970    bytes_ = 0;
1971  }
1972
1973 private:
1974  int number_;
1975  int bytes_;
1976};
1977
1978
1979// HistogramInfo class for recording a single "bar" of a histogram.  This
1980// class is used for collecting statistics to print to the log file.
1981class HistogramInfo: public NumberAndSizeInfo {
1982 public:
1983  HistogramInfo() : NumberAndSizeInfo() {}
1984
1985  const char* name() { return name_; }
1986  void set_name(const char* name) { name_ = name; }
1987
1988 private:
1989  const char* name_;
1990};
1991
1992
1993enum SemiSpaceId {
1994  kFromSpace = 0,
1995  kToSpace = 1
1996};
1997
1998
1999class SemiSpace;
2000
2001
2002class NewSpacePage : public MemoryChunk {
2003 public:
2004  // GC related flags copied from from-space to to-space when
2005  // flipping semispaces.
2006  static const intptr_t kCopyOnFlipFlagsMask =
2007    (1 << MemoryChunk::POINTERS_TO_HERE_ARE_INTERESTING) |
2008    (1 << MemoryChunk::POINTERS_FROM_HERE_ARE_INTERESTING) |
2009    (1 << MemoryChunk::SCAN_ON_SCAVENGE);
2010
2011  static const int kAreaSize = Page::kNonCodeObjectAreaSize;
2012
2013  inline NewSpacePage* next_page() const {
2014    return static_cast<NewSpacePage*>(next_chunk());
2015  }
2016
2017  inline void set_next_page(NewSpacePage* page) {
2018    set_next_chunk(page);
2019  }
2020
2021  inline NewSpacePage* prev_page() const {
2022    return static_cast<NewSpacePage*>(prev_chunk());
2023  }
2024
2025  inline void set_prev_page(NewSpacePage* page) {
2026    set_prev_chunk(page);
2027  }
2028
2029  SemiSpace* semi_space() {
2030    return reinterpret_cast<SemiSpace*>(owner());
2031  }
2032
2033  bool is_anchor() { return !this->InNewSpace(); }
2034
2035  static bool IsAtStart(Address addr) {
2036    return (reinterpret_cast<intptr_t>(addr) & Page::kPageAlignmentMask)
2037        == kObjectStartOffset;
2038  }
2039
2040  static bool IsAtEnd(Address addr) {
2041    return (reinterpret_cast<intptr_t>(addr) & Page::kPageAlignmentMask) == 0;
2042  }
2043
2044  Address address() {
2045    return reinterpret_cast<Address>(this);
2046  }
2047
2048  // Finds the NewSpacePage containg the given address.
2049  static inline NewSpacePage* FromAddress(Address address_in_page) {
2050    Address page_start =
2051        reinterpret_cast<Address>(reinterpret_cast<uintptr_t>(address_in_page) &
2052                                  ~Page::kPageAlignmentMask);
2053    NewSpacePage* page = reinterpret_cast<NewSpacePage*>(page_start);
2054    return page;
2055  }
2056
2057  // Find the page for a limit address. A limit address is either an address
2058  // inside a page, or the address right after the last byte of a page.
2059  static inline NewSpacePage* FromLimit(Address address_limit) {
2060    return NewSpacePage::FromAddress(address_limit - 1);
2061  }
2062
2063 private:
2064  // Create a NewSpacePage object that is only used as anchor
2065  // for the doubly-linked list of real pages.
2066  explicit NewSpacePage(SemiSpace* owner) {
2067    InitializeAsAnchor(owner);
2068  }
2069
2070  static NewSpacePage* Initialize(Heap* heap,
2071                                  Address start,
2072                                  SemiSpace* semi_space);
2073
2074  // Intialize a fake NewSpacePage used as sentinel at the ends
2075  // of a doubly-linked list of real NewSpacePages.
2076  // Only uses the prev/next links, and sets flags to not be in new-space.
2077  void InitializeAsAnchor(SemiSpace* owner);
2078
2079  friend class SemiSpace;
2080  friend class SemiSpaceIterator;
2081};
2082
2083
2084// -----------------------------------------------------------------------------
2085// SemiSpace in young generation
2086//
2087// A semispace is a contiguous chunk of memory holding page-like memory
2088// chunks. The mark-compact collector  uses the memory of the first page in
2089// the from space as a marking stack when tracing live objects.
2090
2091class SemiSpace : public Space {
2092 public:
2093  // Constructor.
2094  SemiSpace(Heap* heap, SemiSpaceId semispace)
2095    : Space(heap, NEW_SPACE, NOT_EXECUTABLE),
2096      start_(NULL),
2097      age_mark_(NULL),
2098      id_(semispace),
2099      anchor_(this),
2100      current_page_(NULL) { }
2101
2102  // Sets up the semispace using the given chunk.
2103  void SetUp(Address start, int initial_capacity, int maximum_capacity);
2104
2105  // Tear down the space.  Heap memory was not allocated by the space, so it
2106  // is not deallocated here.
2107  void TearDown();
2108
2109  // True if the space has been set up but not torn down.
2110  bool HasBeenSetUp() { return start_ != NULL; }
2111
2112  // Grow the semispace to the new capacity.  The new capacity
2113  // requested must be larger than the current capacity and less than
2114  // the maximum capacity.
2115  bool GrowTo(int new_capacity);
2116
2117  // Shrinks the semispace to the new capacity.  The new capacity
2118  // requested must be more than the amount of used memory in the
2119  // semispace and less than the current capacity.
2120  bool ShrinkTo(int new_capacity);
2121
2122  // Returns the start address of the first page of the space.
2123  Address space_start() {
2124    ASSERT(anchor_.next_page() != &anchor_);
2125    return anchor_.next_page()->area_start();
2126  }
2127
2128  // Returns the start address of the current page of the space.
2129  Address page_low() {
2130    return current_page_->area_start();
2131  }
2132
2133  // Returns one past the end address of the space.
2134  Address space_end() {
2135    return anchor_.prev_page()->area_end();
2136  }
2137
2138  // Returns one past the end address of the current page of the space.
2139  Address page_high() {
2140    return current_page_->area_end();
2141  }
2142
2143  bool AdvancePage() {
2144    NewSpacePage* next_page = current_page_->next_page();
2145    if (next_page == anchor()) return false;
2146    current_page_ = next_page;
2147    return true;
2148  }
2149
2150  // Resets the space to using the first page.
2151  void Reset();
2152
2153  // Age mark accessors.
2154  Address age_mark() { return age_mark_; }
2155  void set_age_mark(Address mark);
2156
2157  // True if the address is in the address range of this semispace (not
2158  // necessarily below the allocation pointer).
2159  bool Contains(Address a) {
2160    return (reinterpret_cast<uintptr_t>(a) & address_mask_)
2161           == reinterpret_cast<uintptr_t>(start_);
2162  }
2163
2164  // True if the object is a heap object in the address range of this
2165  // semispace (not necessarily below the allocation pointer).
2166  bool Contains(Object* o) {
2167    return (reinterpret_cast<uintptr_t>(o) & object_mask_) == object_expected_;
2168  }
2169
2170  // If we don't have these here then SemiSpace will be abstract.  However
2171  // they should never be called.
2172  virtual intptr_t Size() {
2173    UNREACHABLE();
2174    return 0;
2175  }
2176
2177  bool is_committed() { return committed_; }
2178  bool Commit();
2179  bool Uncommit();
2180
2181  NewSpacePage* first_page() { return anchor_.next_page(); }
2182  NewSpacePage* current_page() { return current_page_; }
2183
2184#ifdef VERIFY_HEAP
2185  virtual void Verify();
2186#endif
2187
2188#ifdef DEBUG
2189  virtual void Print();
2190  // Validate a range of of addresses in a SemiSpace.
2191  // The "from" address must be on a page prior to the "to" address,
2192  // in the linked page order, or it must be earlier on the same page.
2193  static void AssertValidRange(Address from, Address to);
2194#else
2195  // Do nothing.
2196  inline static void AssertValidRange(Address from, Address to) {}
2197#endif
2198
2199  // Returns the current capacity of the semi space.
2200  int Capacity() { return capacity_; }
2201
2202  // Returns the maximum capacity of the semi space.
2203  int MaximumCapacity() { return maximum_capacity_; }
2204
2205  // Returns the initial capacity of the semi space.
2206  int InitialCapacity() { return initial_capacity_; }
2207
2208  SemiSpaceId id() { return id_; }
2209
2210  static void Swap(SemiSpace* from, SemiSpace* to);
2211
2212  // Returns the maximum amount of memory ever committed by the semi space.
2213  size_t MaximumCommittedMemory() { return maximum_committed_; }
2214
2215  // Approximate amount of physical memory committed for this space.
2216  size_t CommittedPhysicalMemory();
2217
2218 private:
2219  // Flips the semispace between being from-space and to-space.
2220  // Copies the flags into the masked positions on all pages in the space.
2221  void FlipPages(intptr_t flags, intptr_t flag_mask);
2222
2223  // Updates Capacity and MaximumCommitted based on new capacity.
2224  void SetCapacity(int new_capacity);
2225
2226  NewSpacePage* anchor() { return &anchor_; }
2227
2228  // The current and maximum capacity of the space.
2229  int capacity_;
2230  int maximum_capacity_;
2231  int initial_capacity_;
2232
2233  intptr_t maximum_committed_;
2234
2235  // The start address of the space.
2236  Address start_;
2237  // Used to govern object promotion during mark-compact collection.
2238  Address age_mark_;
2239
2240  // Masks and comparison values to test for containment in this semispace.
2241  uintptr_t address_mask_;
2242  uintptr_t object_mask_;
2243  uintptr_t object_expected_;
2244
2245  bool committed_;
2246  SemiSpaceId id_;
2247
2248  NewSpacePage anchor_;
2249  NewSpacePage* current_page_;
2250
2251  friend class SemiSpaceIterator;
2252  friend class NewSpacePageIterator;
2253 public:
2254  TRACK_MEMORY("SemiSpace")
2255};
2256
2257
2258// A SemiSpaceIterator is an ObjectIterator that iterates over the active
2259// semispace of the heap's new space.  It iterates over the objects in the
2260// semispace from a given start address (defaulting to the bottom of the
2261// semispace) to the top of the semispace.  New objects allocated after the
2262// iterator is created are not iterated.
2263class SemiSpaceIterator : public ObjectIterator {
2264 public:
2265  // Create an iterator over the objects in the given space.  If no start
2266  // address is given, the iterator starts from the bottom of the space.  If
2267  // no size function is given, the iterator calls Object::Size().
2268
2269  // Iterate over all of allocated to-space.
2270  explicit SemiSpaceIterator(NewSpace* space);
2271  // Iterate over all of allocated to-space, with a custome size function.
2272  SemiSpaceIterator(NewSpace* space, HeapObjectCallback size_func);
2273  // Iterate over part of allocated to-space, from start to the end
2274  // of allocation.
2275  SemiSpaceIterator(NewSpace* space, Address start);
2276  // Iterate from one address to another in the same semi-space.
2277  SemiSpaceIterator(Address from, Address to);
2278
2279  HeapObject* Next() {
2280    if (current_ == limit_) return NULL;
2281    if (NewSpacePage::IsAtEnd(current_)) {
2282      NewSpacePage* page = NewSpacePage::FromLimit(current_);
2283      page = page->next_page();
2284      ASSERT(!page->is_anchor());
2285      current_ = page->area_start();
2286      if (current_ == limit_) return NULL;
2287    }
2288
2289    HeapObject* object = HeapObject::FromAddress(current_);
2290    int size = (size_func_ == NULL) ? object->Size() : size_func_(object);
2291
2292    current_ += size;
2293    return object;
2294  }
2295
2296  // Implementation of the ObjectIterator functions.
2297  virtual HeapObject* next_object() { return Next(); }
2298
2299 private:
2300  void Initialize(Address start,
2301                  Address end,
2302                  HeapObjectCallback size_func);
2303
2304  // The current iteration point.
2305  Address current_;
2306  // The end of iteration.
2307  Address limit_;
2308  // The callback function.
2309  HeapObjectCallback size_func_;
2310};
2311
2312
2313// -----------------------------------------------------------------------------
2314// A PageIterator iterates the pages in a semi-space.
2315class NewSpacePageIterator BASE_EMBEDDED {
2316 public:
2317  // Make an iterator that runs over all pages in to-space.
2318  explicit inline NewSpacePageIterator(NewSpace* space);
2319
2320  // Make an iterator that runs over all pages in the given semispace,
2321  // even those not used in allocation.
2322  explicit inline NewSpacePageIterator(SemiSpace* space);
2323
2324  // Make iterator that iterates from the page containing start
2325  // to the page that contains limit in the same semispace.
2326  inline NewSpacePageIterator(Address start, Address limit);
2327
2328  inline bool has_next();
2329  inline NewSpacePage* next();
2330
2331 private:
2332  NewSpacePage* prev_page_;  // Previous page returned.
2333  // Next page that will be returned.  Cached here so that we can use this
2334  // iterator for operations that deallocate pages.
2335  NewSpacePage* next_page_;
2336  // Last page returned.
2337  NewSpacePage* last_page_;
2338};
2339
2340
2341// -----------------------------------------------------------------------------
2342// The young generation space.
2343//
2344// The new space consists of a contiguous pair of semispaces.  It simply
2345// forwards most functions to the appropriate semispace.
2346
2347class NewSpace : public Space {
2348 public:
2349  // Constructor.
2350  explicit NewSpace(Heap* heap)
2351    : Space(heap, NEW_SPACE, NOT_EXECUTABLE),
2352      to_space_(heap, kToSpace),
2353      from_space_(heap, kFromSpace),
2354      reservation_(),
2355      inline_allocation_limit_step_(0) {}
2356
2357  // Sets up the new space using the given chunk.
2358  bool SetUp(int reserved_semispace_size_, int max_semispace_size);
2359
2360  // Tears down the space.  Heap memory was not allocated by the space, so it
2361  // is not deallocated here.
2362  void TearDown();
2363
2364  // True if the space has been set up but not torn down.
2365  bool HasBeenSetUp() {
2366    return to_space_.HasBeenSetUp() && from_space_.HasBeenSetUp();
2367  }
2368
2369  // Flip the pair of spaces.
2370  void Flip();
2371
2372  // Grow the capacity of the semispaces.  Assumes that they are not at
2373  // their maximum capacity.
2374  void Grow();
2375
2376  // Shrink the capacity of the semispaces.
2377  void Shrink();
2378
2379  // True if the address or object lies in the address range of either
2380  // semispace (not necessarily below the allocation pointer).
2381  bool Contains(Address a) {
2382    return (reinterpret_cast<uintptr_t>(a) & address_mask_)
2383        == reinterpret_cast<uintptr_t>(start_);
2384  }
2385
2386  bool Contains(Object* o) {
2387    Address a = reinterpret_cast<Address>(o);
2388    return (reinterpret_cast<uintptr_t>(a) & object_mask_) == object_expected_;
2389  }
2390
2391  // Return the allocated bytes in the active semispace.
2392  virtual intptr_t Size() {
2393    return pages_used_ * NewSpacePage::kAreaSize +
2394        static_cast<int>(top() - to_space_.page_low());
2395  }
2396
2397  // The same, but returning an int.  We have to have the one that returns
2398  // intptr_t because it is inherited, but if we know we are dealing with the
2399  // new space, which can't get as big as the other spaces then this is useful:
2400  int SizeAsInt() { return static_cast<int>(Size()); }
2401
2402  // Return the current capacity of a semispace.
2403  intptr_t EffectiveCapacity() {
2404    SLOW_ASSERT(to_space_.Capacity() == from_space_.Capacity());
2405    return (to_space_.Capacity() / Page::kPageSize) * NewSpacePage::kAreaSize;
2406  }
2407
2408  // Return the current capacity of a semispace.
2409  intptr_t Capacity() {
2410    ASSERT(to_space_.Capacity() == from_space_.Capacity());
2411    return to_space_.Capacity();
2412  }
2413
2414  // Return the total amount of memory committed for new space.
2415  intptr_t CommittedMemory() {
2416    if (from_space_.is_committed()) return 2 * Capacity();
2417    return Capacity();
2418  }
2419
2420  // Return the total amount of memory committed for new space.
2421  intptr_t MaximumCommittedMemory() {
2422    return to_space_.MaximumCommittedMemory() +
2423        from_space_.MaximumCommittedMemory();
2424  }
2425
2426  // Approximate amount of physical memory committed for this space.
2427  size_t CommittedPhysicalMemory();
2428
2429  // Return the available bytes without growing.
2430  intptr_t Available() {
2431    return Capacity() - Size();
2432  }
2433
2434  // Return the maximum capacity of a semispace.
2435  int MaximumCapacity() {
2436    ASSERT(to_space_.MaximumCapacity() == from_space_.MaximumCapacity());
2437    return to_space_.MaximumCapacity();
2438  }
2439
2440  // Returns the initial capacity of a semispace.
2441  int InitialCapacity() {
2442    ASSERT(to_space_.InitialCapacity() == from_space_.InitialCapacity());
2443    return to_space_.InitialCapacity();
2444  }
2445
2446  // Return the address of the allocation pointer in the active semispace.
2447  Address top() {
2448    ASSERT(to_space_.current_page()->ContainsLimit(allocation_info_.top()));
2449    return allocation_info_.top();
2450  }
2451
2452  void set_top(Address top) {
2453    ASSERT(to_space_.current_page()->ContainsLimit(top));
2454    allocation_info_.set_top(top);
2455  }
2456
2457  // Return the address of the first object in the active semispace.
2458  Address bottom() { return to_space_.space_start(); }
2459
2460  // Get the age mark of the inactive semispace.
2461  Address age_mark() { return from_space_.age_mark(); }
2462  // Set the age mark in the active semispace.
2463  void set_age_mark(Address mark) { to_space_.set_age_mark(mark); }
2464
2465  // The start address of the space and a bit mask. Anding an address in the
2466  // new space with the mask will result in the start address.
2467  Address start() { return start_; }
2468  uintptr_t mask() { return address_mask_; }
2469
2470  INLINE(uint32_t AddressToMarkbitIndex(Address addr)) {
2471    ASSERT(Contains(addr));
2472    ASSERT(IsAligned(OffsetFrom(addr), kPointerSize) ||
2473           IsAligned(OffsetFrom(addr) - 1, kPointerSize));
2474    return static_cast<uint32_t>(addr - start_) >> kPointerSizeLog2;
2475  }
2476
2477  INLINE(Address MarkbitIndexToAddress(uint32_t index)) {
2478    return reinterpret_cast<Address>(index << kPointerSizeLog2);
2479  }
2480
2481  // The allocation top and limit address.
2482  Address* allocation_top_address() {
2483    return allocation_info_.top_address();
2484  }
2485
2486  // The allocation limit address.
2487  Address* allocation_limit_address() {
2488    return allocation_info_.limit_address();
2489  }
2490
2491  MUST_USE_RESULT INLINE(MaybeObject* AllocateRaw(int size_in_bytes));
2492
2493  // Reset the allocation pointer to the beginning of the active semispace.
2494  void ResetAllocationInfo();
2495
2496  void UpdateInlineAllocationLimit(int size_in_bytes);
2497  void LowerInlineAllocationLimit(intptr_t step) {
2498    inline_allocation_limit_step_ = step;
2499    UpdateInlineAllocationLimit(0);
2500    top_on_previous_step_ = allocation_info_.top();
2501  }
2502
2503  // Get the extent of the inactive semispace (for use as a marking stack,
2504  // or to zap it). Notice: space-addresses are not necessarily on the
2505  // same page, so FromSpaceStart() might be above FromSpaceEnd().
2506  Address FromSpacePageLow() { return from_space_.page_low(); }
2507  Address FromSpacePageHigh() { return from_space_.page_high(); }
2508  Address FromSpaceStart() { return from_space_.space_start(); }
2509  Address FromSpaceEnd() { return from_space_.space_end(); }
2510
2511  // Get the extent of the active semispace's pages' memory.
2512  Address ToSpaceStart() { return to_space_.space_start(); }
2513  Address ToSpaceEnd() { return to_space_.space_end(); }
2514
2515  inline bool ToSpaceContains(Address address) {
2516    return to_space_.Contains(address);
2517  }
2518  inline bool FromSpaceContains(Address address) {
2519    return from_space_.Contains(address);
2520  }
2521
2522  // True if the object is a heap object in the address range of the
2523  // respective semispace (not necessarily below the allocation pointer of the
2524  // semispace).
2525  inline bool ToSpaceContains(Object* o) { return to_space_.Contains(o); }
2526  inline bool FromSpaceContains(Object* o) { return from_space_.Contains(o); }
2527
2528  // Try to switch the active semispace to a new, empty, page.
2529  // Returns false if this isn't possible or reasonable (i.e., there
2530  // are no pages, or the current page is already empty), or true
2531  // if successful.
2532  bool AddFreshPage();
2533
2534#ifdef VERIFY_HEAP
2535  // Verify the active semispace.
2536  virtual void Verify();
2537#endif
2538
2539#ifdef DEBUG
2540  // Print the active semispace.
2541  virtual void Print() { to_space_.Print(); }
2542#endif
2543
2544  // Iterates the active semispace to collect statistics.
2545  void CollectStatistics();
2546  // Reports previously collected statistics of the active semispace.
2547  void ReportStatistics();
2548  // Clears previously collected statistics.
2549  void ClearHistograms();
2550
2551  // Record the allocation or promotion of a heap object.  Note that we don't
2552  // record every single allocation, but only those that happen in the
2553  // to space during a scavenge GC.
2554  void RecordAllocation(HeapObject* obj);
2555  void RecordPromotion(HeapObject* obj);
2556
2557  // Return whether the operation succeded.
2558  bool CommitFromSpaceIfNeeded() {
2559    if (from_space_.is_committed()) return true;
2560    return from_space_.Commit();
2561  }
2562
2563  bool UncommitFromSpace() {
2564    if (!from_space_.is_committed()) return true;
2565    return from_space_.Uncommit();
2566  }
2567
2568  inline intptr_t inline_allocation_limit_step() {
2569    return inline_allocation_limit_step_;
2570  }
2571
2572  SemiSpace* active_space() { return &to_space_; }
2573
2574 private:
2575  // Update allocation info to match the current to-space page.
2576  void UpdateAllocationInfo();
2577
2578  Address chunk_base_;
2579  uintptr_t chunk_size_;
2580
2581  // The semispaces.
2582  SemiSpace to_space_;
2583  SemiSpace from_space_;
2584  VirtualMemory reservation_;
2585  int pages_used_;
2586
2587  // Start address and bit mask for containment testing.
2588  Address start_;
2589  uintptr_t address_mask_;
2590  uintptr_t object_mask_;
2591  uintptr_t object_expected_;
2592
2593  // Allocation pointer and limit for normal allocation and allocation during
2594  // mark-compact collection.
2595  AllocationInfo allocation_info_;
2596
2597  // When incremental marking is active we will set allocation_info_.limit
2598  // to be lower than actual limit and then will gradually increase it
2599  // in steps to guarantee that we do incremental marking steps even
2600  // when all allocation is performed from inlined generated code.
2601  intptr_t inline_allocation_limit_step_;
2602
2603  Address top_on_previous_step_;
2604
2605  HistogramInfo* allocated_histogram_;
2606  HistogramInfo* promoted_histogram_;
2607
2608  MUST_USE_RESULT MaybeObject* SlowAllocateRaw(int size_in_bytes);
2609
2610  friend class SemiSpaceIterator;
2611
2612 public:
2613  TRACK_MEMORY("NewSpace")
2614};
2615
2616
2617// -----------------------------------------------------------------------------
2618// Old object space (excluding map objects)
2619
2620class OldSpace : public PagedSpace {
2621 public:
2622  // Creates an old space object with a given maximum capacity.
2623  // The constructor does not allocate pages from OS.
2624  OldSpace(Heap* heap,
2625           intptr_t max_capacity,
2626           AllocationSpace id,
2627           Executability executable)
2628      : PagedSpace(heap, max_capacity, id, executable) {
2629  }
2630
2631 public:
2632  TRACK_MEMORY("OldSpace")
2633};
2634
2635
2636// For contiguous spaces, top should be in the space (or at the end) and limit
2637// should be the end of the space.
2638#define ASSERT_SEMISPACE_ALLOCATION_INFO(info, space) \
2639  SLOW_ASSERT((space).page_low() <= (info).top() \
2640              && (info).top() <= (space).page_high() \
2641              && (info).limit() <= (space).page_high())
2642
2643
2644// -----------------------------------------------------------------------------
2645// Old space for all map objects
2646
2647class MapSpace : public PagedSpace {
2648 public:
2649  // Creates a map space object with a maximum capacity.
2650  MapSpace(Heap* heap, intptr_t max_capacity, AllocationSpace id)
2651      : PagedSpace(heap, max_capacity, id, NOT_EXECUTABLE),
2652        max_map_space_pages_(kMaxMapPageIndex - 1) {
2653  }
2654
2655  // Given an index, returns the page address.
2656  // TODO(1600): this limit is artifical just to keep code compilable
2657  static const int kMaxMapPageIndex = 1 << 16;
2658
2659  virtual int RoundSizeDownToObjectAlignment(int size) {
2660    if (IsPowerOf2(Map::kSize)) {
2661      return RoundDown(size, Map::kSize);
2662    } else {
2663      return (size / Map::kSize) * Map::kSize;
2664    }
2665  }
2666
2667 protected:
2668  virtual void VerifyObject(HeapObject* obj);
2669
2670 private:
2671  static const int kMapsPerPage = Page::kNonCodeObjectAreaSize / Map::kSize;
2672
2673  // Do map space compaction if there is a page gap.
2674  int CompactionThreshold() {
2675    return kMapsPerPage * (max_map_space_pages_ - 1);
2676  }
2677
2678  const int max_map_space_pages_;
2679
2680 public:
2681  TRACK_MEMORY("MapSpace")
2682};
2683
2684
2685// -----------------------------------------------------------------------------
2686// Old space for simple property cell objects
2687
2688class CellSpace : public PagedSpace {
2689 public:
2690  // Creates a property cell space object with a maximum capacity.
2691  CellSpace(Heap* heap, intptr_t max_capacity, AllocationSpace id)
2692      : PagedSpace(heap, max_capacity, id, NOT_EXECUTABLE) {
2693  }
2694
2695  virtual int RoundSizeDownToObjectAlignment(int size) {
2696    if (IsPowerOf2(Cell::kSize)) {
2697      return RoundDown(size, Cell::kSize);
2698    } else {
2699      return (size / Cell::kSize) * Cell::kSize;
2700    }
2701  }
2702
2703 protected:
2704  virtual void VerifyObject(HeapObject* obj);
2705
2706 public:
2707  TRACK_MEMORY("CellSpace")
2708};
2709
2710
2711// -----------------------------------------------------------------------------
2712// Old space for all global object property cell objects
2713
2714class PropertyCellSpace : public PagedSpace {
2715 public:
2716  // Creates a property cell space object with a maximum capacity.
2717  PropertyCellSpace(Heap* heap, intptr_t max_capacity,
2718                    AllocationSpace id)
2719      : PagedSpace(heap, max_capacity, id, NOT_EXECUTABLE) {
2720  }
2721
2722  virtual int RoundSizeDownToObjectAlignment(int size) {
2723    if (IsPowerOf2(PropertyCell::kSize)) {
2724      return RoundDown(size, PropertyCell::kSize);
2725    } else {
2726      return (size / PropertyCell::kSize) * PropertyCell::kSize;
2727    }
2728  }
2729
2730 protected:
2731  virtual void VerifyObject(HeapObject* obj);
2732
2733 public:
2734  TRACK_MEMORY("PropertyCellSpace")
2735};
2736
2737
2738// -----------------------------------------------------------------------------
2739// Large objects ( > Page::kMaxHeapObjectSize ) are allocated and managed by
2740// the large object space. A large object is allocated from OS heap with
2741// extra padding bytes (Page::kPageSize + Page::kObjectStartOffset).
2742// A large object always starts at Page::kObjectStartOffset to a page.
2743// Large objects do not move during garbage collections.
2744
2745class LargeObjectSpace : public Space {
2746 public:
2747  LargeObjectSpace(Heap* heap, intptr_t max_capacity, AllocationSpace id);
2748  virtual ~LargeObjectSpace() {}
2749
2750  // Initializes internal data structures.
2751  bool SetUp();
2752
2753  // Releases internal resources, frees objects in this space.
2754  void TearDown();
2755
2756  static intptr_t ObjectSizeFor(intptr_t chunk_size) {
2757    if (chunk_size <= (Page::kPageSize + Page::kObjectStartOffset)) return 0;
2758    return chunk_size - Page::kPageSize - Page::kObjectStartOffset;
2759  }
2760
2761  // Shared implementation of AllocateRaw, AllocateRawCode and
2762  // AllocateRawFixedArray.
2763  MUST_USE_RESULT MaybeObject* AllocateRaw(int object_size,
2764                                           Executability executable);
2765
2766  // Available bytes for objects in this space.
2767  inline intptr_t Available();
2768
2769  virtual intptr_t Size() {
2770    return size_;
2771  }
2772
2773  virtual intptr_t SizeOfObjects() {
2774    return objects_size_;
2775  }
2776
2777  intptr_t MaximumCommittedMemory() {
2778    return maximum_committed_;
2779  }
2780
2781  intptr_t CommittedMemory() {
2782    return Size();
2783  }
2784
2785  // Approximate amount of physical memory committed for this space.
2786  size_t CommittedPhysicalMemory();
2787
2788  int PageCount() {
2789    return page_count_;
2790  }
2791
2792  // Finds an object for a given address, returns Failure::Exception()
2793  // if it is not found. The function iterates through all objects in this
2794  // space, may be slow.
2795  MaybeObject* FindObject(Address a);
2796
2797  // Finds a large object page containing the given address, returns NULL
2798  // if such a page doesn't exist.
2799  LargePage* FindPage(Address a);
2800
2801  // Frees unmarked objects.
2802  void FreeUnmarkedObjects();
2803
2804  // Checks whether a heap object is in this space; O(1).
2805  bool Contains(HeapObject* obj);
2806
2807  // Checks whether the space is empty.
2808  bool IsEmpty() { return first_page_ == NULL; }
2809
2810  LargePage* first_page() { return first_page_; }
2811
2812#ifdef VERIFY_HEAP
2813  virtual void Verify();
2814#endif
2815
2816#ifdef DEBUG
2817  virtual void Print();
2818  void ReportStatistics();
2819  void CollectCodeStatistics();
2820#endif
2821  // Checks whether an address is in the object area in this space.  It
2822  // iterates all objects in the space. May be slow.
2823  bool SlowContains(Address addr) { return !FindObject(addr)->IsFailure(); }
2824
2825 private:
2826  intptr_t max_capacity_;
2827  intptr_t maximum_committed_;
2828  // The head of the linked list of large object chunks.
2829  LargePage* first_page_;
2830  intptr_t size_;  // allocated bytes
2831  int page_count_;  // number of chunks
2832  intptr_t objects_size_;  // size of objects
2833  // Map MemoryChunk::kAlignment-aligned chunks to large pages covering them
2834  HashMap chunk_map_;
2835
2836  friend class LargeObjectIterator;
2837
2838 public:
2839  TRACK_MEMORY("LargeObjectSpace")
2840};
2841
2842
2843class LargeObjectIterator: public ObjectIterator {
2844 public:
2845  explicit LargeObjectIterator(LargeObjectSpace* space);
2846  LargeObjectIterator(LargeObjectSpace* space, HeapObjectCallback size_func);
2847
2848  HeapObject* Next();
2849
2850  // implementation of ObjectIterator.
2851  virtual HeapObject* next_object() { return Next(); }
2852
2853 private:
2854  LargePage* current_;
2855  HeapObjectCallback size_func_;
2856};
2857
2858
2859// Iterates over the chunks (pages and large object pages) that can contain
2860// pointers to new space.
2861class PointerChunkIterator BASE_EMBEDDED {
2862 public:
2863  inline explicit PointerChunkIterator(Heap* heap);
2864
2865  // Return NULL when the iterator is done.
2866  MemoryChunk* next() {
2867    switch (state_) {
2868      case kOldPointerState: {
2869        if (old_pointer_iterator_.has_next()) {
2870          return old_pointer_iterator_.next();
2871        }
2872        state_ = kMapState;
2873        // Fall through.
2874      }
2875      case kMapState: {
2876        if (map_iterator_.has_next()) {
2877          return map_iterator_.next();
2878        }
2879        state_ = kLargeObjectState;
2880        // Fall through.
2881      }
2882      case kLargeObjectState: {
2883        HeapObject* heap_object;
2884        do {
2885          heap_object = lo_iterator_.Next();
2886          if (heap_object == NULL) {
2887            state_ = kFinishedState;
2888            return NULL;
2889          }
2890          // Fixed arrays are the only pointer-containing objects in large
2891          // object space.
2892        } while (!heap_object->IsFixedArray());
2893        MemoryChunk* answer = MemoryChunk::FromAddress(heap_object->address());
2894        return answer;
2895      }
2896      case kFinishedState:
2897        return NULL;
2898      default:
2899        break;
2900    }
2901    UNREACHABLE();
2902    return NULL;
2903  }
2904
2905
2906 private:
2907  enum State {
2908    kOldPointerState,
2909    kMapState,
2910    kLargeObjectState,
2911    kFinishedState
2912  };
2913  State state_;
2914  PageIterator old_pointer_iterator_;
2915  PageIterator map_iterator_;
2916  LargeObjectIterator lo_iterator_;
2917};
2918
2919
2920#ifdef DEBUG
2921struct CommentStatistic {
2922  const char* comment;
2923  int size;
2924  int count;
2925  void Clear() {
2926    comment = NULL;
2927    size = 0;
2928    count = 0;
2929  }
2930  // Must be small, since an iteration is used for lookup.
2931  static const int kMaxComments = 64;
2932};
2933#endif
2934
2935
2936} }  // namespace v8::internal
2937
2938#endif  // V8_SPACES_H_
2939