| Index: src/heap/spaces.h
 | 
| diff --git a/src/heap/spaces.h b/src/heap/spaces.h
 | 
| index b8fc9b7efe0845d4852b6660c8465abdda18f115..bf958a48069decb3a9c0e231010fc19361637006 100644
 | 
| --- a/src/heap/spaces.h
 | 
| +++ b/src/heap/spaces.h
 | 
| @@ -268,6 +268,44 @@ class SlotsBuffer;
 | 
|  // any heap object.
 | 
|  class MemoryChunk {
 | 
|   public:
 | 
| +  enum MemoryChunkFlags {
 | 
| +    IS_EXECUTABLE,
 | 
| +    ABOUT_TO_BE_FREED,
 | 
| +    POINTERS_TO_HERE_ARE_INTERESTING,
 | 
| +    POINTERS_FROM_HERE_ARE_INTERESTING,
 | 
| +    SCAN_ON_SCAVENGE,
 | 
| +    IN_FROM_SPACE,  // Mutually exclusive with IN_TO_SPACE.
 | 
| +    IN_TO_SPACE,    // All pages in new space has one of these two set.
 | 
| +    NEW_SPACE_BELOW_AGE_MARK,
 | 
| +    EVACUATION_CANDIDATE,
 | 
| +    RESCAN_ON_EVACUATION,
 | 
| +    NEVER_EVACUATE,  // May contain immortal immutables.
 | 
| +    POPULAR_PAGE,    // Slots buffer of this page overflowed on the previous GC.
 | 
| +
 | 
| +    // WAS_SWEPT indicates that marking bits have been cleared by the sweeper,
 | 
| +    // otherwise marking bits are still intact.
 | 
| +    WAS_SWEPT,
 | 
| +
 | 
| +    // Large objects can have a progress bar in their page header. These object
 | 
| +    // are scanned in increments and will be kept black while being scanned.
 | 
| +    // Even if the mutator writes to them they will be kept black and a white
 | 
| +    // to grey transition is performed in the value.
 | 
| +    HAS_PROGRESS_BAR,
 | 
| +
 | 
| +    // This flag is intended to be used for testing. Works only when both
 | 
| +    // FLAG_stress_compaction and FLAG_manual_evacuation_candidates_selection
 | 
| +    // are set. It forces the page to become an evacuation candidate at next
 | 
| +    // candidates selection cycle.
 | 
| +    FORCE_EVACUATION_CANDIDATE_FOR_TESTING,
 | 
| +
 | 
| +    // The memory chunk is already logically freed, however the actual freeing
 | 
| +    // still has to be performed.
 | 
| +    PRE_FREED,
 | 
| +
 | 
| +    // Last flag, keep at bottom.
 | 
| +    NUM_MEMORY_CHUNK_FLAGS
 | 
| +  };
 | 
| +
 | 
|    // |kCompactionDone|: Initial compaction state of a |MemoryChunk|.
 | 
|    // |kCompactingInProgress|:  Parallel compaction is currently in progress.
 | 
|    // |kCompactingFinalize|: Parallel compaction is done but the chunk needs to
 | 
| @@ -294,37 +332,126 @@ class MemoryChunk {
 | 
|      kSweepingPending
 | 
|    };
 | 
|  
 | 
| +  // Every n write barrier invocations we go to runtime even though
 | 
| +  // we could have handled it in generated code.  This lets us check
 | 
| +  // whether we have hit the limit and should do some more marking.
 | 
| +  static const int kWriteBarrierCounterGranularity = 500;
 | 
| +
 | 
| +  static const int kPointersToHereAreInterestingMask =
 | 
| +      1 << POINTERS_TO_HERE_ARE_INTERESTING;
 | 
| +
 | 
| +  static const int kPointersFromHereAreInterestingMask =
 | 
| +      1 << POINTERS_FROM_HERE_ARE_INTERESTING;
 | 
| +
 | 
| +  static const int kEvacuationCandidateMask = 1 << EVACUATION_CANDIDATE;
 | 
| +
 | 
| +  static const int kSkipEvacuationSlotsRecordingMask =
 | 
| +      (1 << EVACUATION_CANDIDATE) | (1 << RESCAN_ON_EVACUATION) |
 | 
| +      (1 << IN_FROM_SPACE) | (1 << IN_TO_SPACE);
 | 
| +
 | 
| +  static const intptr_t kAlignment =
 | 
| +      (static_cast<uintptr_t>(1) << kPageSizeBits);
 | 
| +
 | 
| +  static const intptr_t kAlignmentMask = kAlignment - 1;
 | 
| +
 | 
| +  static const intptr_t kSizeOffset = 0;
 | 
| +
 | 
| +  static const intptr_t kLiveBytesOffset =
 | 
| +      kSizeOffset + kPointerSize  // size_t size
 | 
| +      + kIntptrSize               // intptr_t flags_
 | 
| +      + kPointerSize              // Address area_start_
 | 
| +      + kPointerSize              // Address area_end_
 | 
| +      + 2 * kPointerSize          // base::VirtualMemory reservation_
 | 
| +      + kPointerSize              // Address owner_
 | 
| +      + kPointerSize              // Heap* heap_
 | 
| +      + kIntSize;                 // int store_buffer_counter_
 | 
| +
 | 
| +  static const size_t kSlotsBufferOffset =
 | 
| +      kLiveBytesOffset + kIntSize;  // int live_byte_count_
 | 
| +
 | 
| +  static const size_t kWriteBarrierCounterOffset =
 | 
| +      kSlotsBufferOffset + kPointerSize  // SlotsBuffer* slots_buffer_;
 | 
| +      + kPointerSize;                    // SkipList* skip_list_;
 | 
| +
 | 
| +  static const size_t kMinHeaderSize =
 | 
| +      kWriteBarrierCounterOffset +
 | 
| +      kIntptrSize         // intptr_t write_barrier_counter_
 | 
| +      + kIntSize          // int progress_bar_
 | 
| +      + kPointerSize      // AtomicValue high_water_mark_
 | 
| +      + kPointerSize      // base::Mutex* mutex_
 | 
| +      + kPointerSize      // base::AtomicWord parallel_sweeping_
 | 
| +      + kPointerSize      // AtomicValue parallel_compaction_
 | 
| +      + 5 * kPointerSize  // AtomicNumber free-list statistics
 | 
| +      + kPointerSize      // AtomicValue next_chunk_
 | 
| +      + kPointerSize;     // AtomicValue prev_chunk_
 | 
| +
 | 
| +  // We add some more space to the computed header size to amount for missing
 | 
| +  // alignment requirements in our computation.
 | 
| +  // Try to get kHeaderSize properly aligned on 32-bit and 64-bit machines.
 | 
| +  static const size_t kHeaderSize = kMinHeaderSize + kIntSize;
 | 
| +
 | 
| +  static const int kBodyOffset =
 | 
| +      CODE_POINTER_ALIGN(kHeaderSize + Bitmap::kSize);
 | 
| +
 | 
| +  // The start offset of the object area in a page. Aligned to both maps and
 | 
| +  // code alignment to be suitable for both.  Also aligned to 32 words because
 | 
| +  // the marking bitmap is arranged in 32 bit chunks.
 | 
| +  static const int kObjectStartAlignment = 32 * kPointerSize;
 | 
| +  static const int kObjectStartOffset =
 | 
| +      kBodyOffset - 1 +
 | 
| +      (kObjectStartAlignment - (kBodyOffset - 1) % kObjectStartAlignment);
 | 
| +
 | 
| +  static const int kFlagsOffset = kPointerSize;
 | 
| +
 | 
| +  static void IncrementLiveBytesFromMutator(HeapObject* object, int by);
 | 
| +
 | 
|    // Only works if the pointer is in the first kPageSize of the MemoryChunk.
 | 
|    static MemoryChunk* FromAddress(Address a) {
 | 
|      return reinterpret_cast<MemoryChunk*>(OffsetFrom(a) & ~kAlignmentMask);
 | 
|    }
 | 
| +
 | 
|    static const MemoryChunk* FromAddress(const byte* a) {
 | 
|      return reinterpret_cast<const MemoryChunk*>(OffsetFrom(a) &
 | 
|                                                  ~kAlignmentMask);
 | 
|    }
 | 
|  
 | 
| +  static void IncrementLiveBytesFromGC(HeapObject* object, int by) {
 | 
| +    MemoryChunk::FromAddress(object->address())->IncrementLiveBytes(by);
 | 
| +  }
 | 
| +
 | 
|    // Only works for addresses in pointer spaces, not data or code spaces.
 | 
|    static inline MemoryChunk* FromAnyPointerAddress(Heap* heap, Address addr);
 | 
|  
 | 
| +  static inline uint32_t FastAddressToMarkbitIndex(Address addr) {
 | 
| +    const intptr_t offset = reinterpret_cast<intptr_t>(addr) & kAlignmentMask;
 | 
| +    return static_cast<uint32_t>(offset) >> kPointerSizeLog2;
 | 
| +  }
 | 
| +
 | 
| +  static inline void UpdateHighWaterMark(Address mark) {
 | 
| +    if (mark == nullptr) return;
 | 
| +    // Need to subtract one from the mark because when a chunk is full the
 | 
| +    // top points to the next address after the chunk, which effectively belongs
 | 
| +    // to another chunk. See the comment to Page::FromAllocationTop.
 | 
| +    MemoryChunk* chunk = MemoryChunk::FromAddress(mark - 1);
 | 
| +    intptr_t new_mark = static_cast<intptr_t>(mark - chunk->address());
 | 
| +    intptr_t old_mark = 0;
 | 
| +    do {
 | 
| +      old_mark = chunk->high_water_mark_.Value();
 | 
| +    } while ((new_mark > old_mark) &&
 | 
| +             !chunk->high_water_mark_.TrySetValue(old_mark, new_mark));
 | 
| +  }
 | 
| +
 | 
|    Address address() { return reinterpret_cast<Address>(this); }
 | 
|  
 | 
|    bool is_valid() { return address() != NULL; }
 | 
|  
 | 
| -  MemoryChunk* next_chunk() const {
 | 
| -    return reinterpret_cast<MemoryChunk*>(base::Acquire_Load(&next_chunk_));
 | 
| -  }
 | 
| +  MemoryChunk* next_chunk() { return next_chunk_.Value(); }
 | 
|  
 | 
| -  MemoryChunk* prev_chunk() const {
 | 
| -    return reinterpret_cast<MemoryChunk*>(base::Acquire_Load(&prev_chunk_));
 | 
| -  }
 | 
| +  MemoryChunk* prev_chunk() { return prev_chunk_.Value(); }
 | 
|  
 | 
| -  void set_next_chunk(MemoryChunk* next) {
 | 
| -    base::Release_Store(&next_chunk_, reinterpret_cast<base::AtomicWord>(next));
 | 
| -  }
 | 
| +  void set_next_chunk(MemoryChunk* next) { next_chunk_.SetValue(next); }
 | 
|  
 | 
| -  void set_prev_chunk(MemoryChunk* prev) {
 | 
| -    base::Release_Store(&prev_chunk_, reinterpret_cast<base::AtomicWord>(prev));
 | 
| -  }
 | 
| +  void set_prev_chunk(MemoryChunk* prev) { prev_chunk_.SetValue(prev); }
 | 
|  
 | 
|    Space* owner() const {
 | 
|      if ((reinterpret_cast<intptr_t>(owner_) & kPageHeaderTagMask) ==
 | 
| @@ -345,8 +472,6 @@ class MemoryChunk {
 | 
|  
 | 
|    base::VirtualMemory* reserved_memory() { return &reservation_; }
 | 
|  
 | 
| -  void InitializeReservedMemory() { reservation_.Reset(); }
 | 
| -
 | 
|    void set_reserved_memory(base::VirtualMemory* reservation) {
 | 
|      DCHECK_NOT_NULL(reservation);
 | 
|      reservation_.TakeControl(reservation);
 | 
| @@ -378,63 +503,6 @@ class MemoryChunk {
 | 
|      return addr >= area_start() && addr <= area_end();
 | 
|    }
 | 
|  
 | 
| -  // Every n write barrier invocations we go to runtime even though
 | 
| -  // we could have handled it in generated code.  This lets us check
 | 
| -  // whether we have hit the limit and should do some more marking.
 | 
| -  static const int kWriteBarrierCounterGranularity = 500;
 | 
| -
 | 
| -  enum MemoryChunkFlags {
 | 
| -    IS_EXECUTABLE,
 | 
| -    ABOUT_TO_BE_FREED,
 | 
| -    POINTERS_TO_HERE_ARE_INTERESTING,
 | 
| -    POINTERS_FROM_HERE_ARE_INTERESTING,
 | 
| -    SCAN_ON_SCAVENGE,
 | 
| -    IN_FROM_SPACE,  // Mutually exclusive with IN_TO_SPACE.
 | 
| -    IN_TO_SPACE,    // All pages in new space has one of these two set.
 | 
| -    NEW_SPACE_BELOW_AGE_MARK,
 | 
| -    EVACUATION_CANDIDATE,
 | 
| -    RESCAN_ON_EVACUATION,
 | 
| -    NEVER_EVACUATE,  // May contain immortal immutables.
 | 
| -    POPULAR_PAGE,    // Slots buffer of this page overflowed on the previous GC.
 | 
| -
 | 
| -    // WAS_SWEPT indicates that marking bits have been cleared by the sweeper,
 | 
| -    // otherwise marking bits are still intact.
 | 
| -    WAS_SWEPT,
 | 
| -
 | 
| -    // Large objects can have a progress bar in their page header. These object
 | 
| -    // are scanned in increments and will be kept black while being scanned.
 | 
| -    // Even if the mutator writes to them they will be kept black and a white
 | 
| -    // to grey transition is performed in the value.
 | 
| -    HAS_PROGRESS_BAR,
 | 
| -
 | 
| -    // This flag is intended to be used for testing. Works only when both
 | 
| -    // FLAG_stress_compaction and FLAG_manual_evacuation_candidates_selection
 | 
| -    // are set. It forces the page to become an evacuation candidate at next
 | 
| -    // candidates selection cycle.
 | 
| -    FORCE_EVACUATION_CANDIDATE_FOR_TESTING,
 | 
| -
 | 
| -    // The memory chunk is already logically freed, however the actual freeing
 | 
| -    // still has to be performed.
 | 
| -    PRE_FREED,
 | 
| -
 | 
| -    // Last flag, keep at bottom.
 | 
| -    NUM_MEMORY_CHUNK_FLAGS
 | 
| -  };
 | 
| -
 | 
| -
 | 
| -  static const int kPointersToHereAreInterestingMask =
 | 
| -      1 << POINTERS_TO_HERE_ARE_INTERESTING;
 | 
| -
 | 
| -  static const int kPointersFromHereAreInterestingMask =
 | 
| -      1 << POINTERS_FROM_HERE_ARE_INTERESTING;
 | 
| -
 | 
| -  static const int kEvacuationCandidateMask = 1 << EVACUATION_CANDIDATE;
 | 
| -
 | 
| -  static const int kSkipEvacuationSlotsRecordingMask =
 | 
| -      (1 << EVACUATION_CANDIDATE) | (1 << RESCAN_ON_EVACUATION) |
 | 
| -      (1 << IN_FROM_SPACE) | (1 << IN_TO_SPACE);
 | 
| -
 | 
| -
 | 
|    void SetFlag(int flag) { flags_ |= static_cast<uintptr_t>(1) << flag; }
 | 
|  
 | 
|    void ClearFlag(int flag) { flags_ &= ~(static_cast<uintptr_t>(1) << flag); }
 | 
| @@ -541,65 +609,6 @@ class MemoryChunk {
 | 
|             progress_bar();
 | 
|    }
 | 
|  
 | 
| -  static void IncrementLiveBytesFromGC(HeapObject* object, int by) {
 | 
| -    MemoryChunk::FromAddress(object->address())->IncrementLiveBytes(by);
 | 
| -  }
 | 
| -
 | 
| -  static void IncrementLiveBytesFromMutator(HeapObject* object, int by);
 | 
| -
 | 
| -  static const intptr_t kAlignment =
 | 
| -      (static_cast<uintptr_t>(1) << kPageSizeBits);
 | 
| -
 | 
| -  static const intptr_t kAlignmentMask = kAlignment - 1;
 | 
| -
 | 
| -  static const intptr_t kSizeOffset = 0;
 | 
| -
 | 
| -  static const intptr_t kLiveBytesOffset =
 | 
| -      kSizeOffset + kPointerSize  // size_t size
 | 
| -      + kIntptrSize               // intptr_t flags_
 | 
| -      + kPointerSize              // Address area_start_
 | 
| -      + kPointerSize              // Address area_end_
 | 
| -      + 2 * kPointerSize          // base::VirtualMemory reservation_
 | 
| -      + kPointerSize              // Address owner_
 | 
| -      + kPointerSize              // Heap* heap_
 | 
| -      + kIntSize;                 // int store_buffer_counter_
 | 
| -
 | 
| -
 | 
| -  static const size_t kSlotsBufferOffset =
 | 
| -      kLiveBytesOffset + kIntSize;  // int live_byte_count_
 | 
| -
 | 
| -  static const size_t kWriteBarrierCounterOffset =
 | 
| -      kSlotsBufferOffset + kPointerSize  // SlotsBuffer* slots_buffer_;
 | 
| -      + kPointerSize;                    // SkipList* skip_list_;
 | 
| -
 | 
| -  static const size_t kMinHeaderSize =
 | 
| -      kWriteBarrierCounterOffset +
 | 
| -      kIntptrSize         // intptr_t write_barrier_counter_
 | 
| -      + kIntSize          // int progress_bar_
 | 
| -      + kPointerSize      // AtomicValue high_water_mark_
 | 
| -      + kPointerSize      // base::Mutex* mutex_
 | 
| -      + kPointerSize      // base::AtomicWord parallel_sweeping_
 | 
| -      + kPointerSize      // AtomicValue parallel_compaction_
 | 
| -      + 5 * kPointerSize  // AtomicNumber free-list statistics
 | 
| -      + kPointerSize      // base::AtomicWord next_chunk_
 | 
| -      + kPointerSize;     // base::AtomicWord prev_chunk_
 | 
| -
 | 
| -  // We add some more space to the computed header size to amount for missing
 | 
| -  // alignment requirements in our computation.
 | 
| -  // Try to get kHeaderSize properly aligned on 32-bit and 64-bit machines.
 | 
| -  static const size_t kHeaderSize = kMinHeaderSize + kIntSize;
 | 
| -
 | 
| -  static const int kBodyOffset =
 | 
| -      CODE_POINTER_ALIGN(kHeaderSize + Bitmap::kSize);
 | 
| -
 | 
| -  // The start offset of the object area in a page. Aligned to both maps and
 | 
| -  // code alignment to be suitable for both.  Also aligned to 32 words because
 | 
| -  // the marking bitmap is arranged in 32 bit chunks.
 | 
| -  static const int kObjectStartAlignment = 32 * kPointerSize;
 | 
| -  static const int kObjectStartOffset =
 | 
| -      kBodyOffset - 1 +
 | 
| -      (kObjectStartAlignment - (kBodyOffset - 1) % kObjectStartAlignment);
 | 
| -
 | 
|    size_t size() const { return size_; }
 | 
|  
 | 
|    void set_size(size_t size) { size_ = size; }
 | 
| @@ -621,7 +630,6 @@ class MemoryChunk {
 | 
|  
 | 
|    bool InFromSpace() { return IsFlagSet(IN_FROM_SPACE); }
 | 
|  
 | 
| -  // ---------------------------------------------------------------------
 | 
|    // Markbits support
 | 
|  
 | 
|    inline Bitmap* markbits() {
 | 
| @@ -634,12 +642,6 @@ class MemoryChunk {
 | 
|      return static_cast<uint32_t>(addr - this->address()) >> kPointerSizeLog2;
 | 
|    }
 | 
|  
 | 
| -  inline static uint32_t FastAddressToMarkbitIndex(Address addr) {
 | 
| -    const intptr_t offset = reinterpret_cast<intptr_t>(addr) & kAlignmentMask;
 | 
| -
 | 
| -    return static_cast<uint32_t>(offset) >> kPointerSizeLog2;
 | 
| -  }
 | 
| -
 | 
|    inline Address MarkbitIndexToAddress(uint32_t index) {
 | 
|      return this->address() + (index << kPointerSizeLog2);
 | 
|    }
 | 
| @@ -649,8 +651,6 @@ class MemoryChunk {
 | 
|  
 | 
|    inline Heap* heap() const { return heap_; }
 | 
|  
 | 
| -  static const int kFlagsOffset = kPointerSize;
 | 
| -
 | 
|    bool NeverEvacuate() { return IsFlagSet(NEVER_EVACUATE); }
 | 
|  
 | 
|    void MarkNeverEvacuate() { SetFlag(NEVER_EVACUATE); }
 | 
| @@ -694,21 +694,11 @@ class MemoryChunk {
 | 
|    // Should be called when memory chunk is about to be freed.
 | 
|    void ReleaseAllocatedMemory();
 | 
|  
 | 
| -  static inline void UpdateHighWaterMark(Address mark) {
 | 
| -    if (mark == nullptr) return;
 | 
| -    // Need to subtract one from the mark because when a chunk is full the
 | 
| -    // top points to the next address after the chunk, which effectively belongs
 | 
| -    // to another chunk. See the comment to Page::FromAllocationTop.
 | 
| -    MemoryChunk* chunk = MemoryChunk::FromAddress(mark - 1);
 | 
| -    intptr_t new_mark = static_cast<intptr_t>(mark - chunk->address());
 | 
| -    intptr_t old_mark = 0;
 | 
| -    do {
 | 
| -      old_mark = chunk->high_water_mark_.Value();
 | 
| -    } while ((new_mark > old_mark) &&
 | 
| -             !chunk->high_water_mark_.TrySetValue(old_mark, new_mark));
 | 
| -  }
 | 
| -
 | 
|   protected:
 | 
| +  static MemoryChunk* Initialize(Heap* heap, Address base, size_t size,
 | 
| +                                 Address area_start, Address area_end,
 | 
| +                                 Executability executable, Space* owner);
 | 
| +
 | 
|    size_t size_;
 | 
|    intptr_t flags_;
 | 
|  
 | 
| @@ -750,15 +740,13 @@ class MemoryChunk {
 | 
|    AtomicNumber<intptr_t> non_available_small_blocks_;
 | 
|  
 | 
|    // next_chunk_ holds a pointer of type MemoryChunk
 | 
| -  base::AtomicWord next_chunk_;
 | 
| +  AtomicValue<MemoryChunk*> next_chunk_;
 | 
|    // prev_chunk_ holds a pointer of type MemoryChunk
 | 
| -  base::AtomicWord prev_chunk_;
 | 
| -
 | 
| -  static MemoryChunk* Initialize(Heap* heap, Address base, size_t size,
 | 
| -                                 Address area_start, Address area_end,
 | 
| -                                 Executability executable, Space* owner);
 | 
| +  AtomicValue<MemoryChunk*> prev_chunk_;
 | 
|  
 | 
|   private:
 | 
| +  void InitializeReservedMemory() { reservation_.Reset(); }
 | 
| +
 | 
|    friend class MemoryAllocator;
 | 
|    friend class MemoryChunkValidator;
 | 
|  };
 | 
| @@ -877,7 +865,7 @@ class LargePage : public MemoryChunk {
 | 
|   public:
 | 
|    HeapObject* GetObject() { return HeapObject::FromAddress(area_start()); }
 | 
|  
 | 
| -  inline LargePage* next_page() const {
 | 
| +  inline LargePage* next_page() {
 | 
|      return static_cast<LargePage*>(next_chunk());
 | 
|    }
 | 
|  
 | 
| @@ -2117,13 +2105,13 @@ class NewSpacePage : public MemoryChunk {
 | 
|  
 | 
|    static const int kAreaSize = Page::kMaxRegularHeapObjectSize;
 | 
|  
 | 
| -  inline NewSpacePage* next_page() const {
 | 
| +  inline NewSpacePage* next_page() {
 | 
|      return static_cast<NewSpacePage*>(next_chunk());
 | 
|    }
 | 
|  
 | 
|    inline void set_next_page(NewSpacePage* page) { set_next_chunk(page); }
 | 
|  
 | 
| -  inline NewSpacePage* prev_page() const {
 | 
| +  inline NewSpacePage* prev_page() {
 | 
|      return static_cast<NewSpacePage*>(prev_chunk());
 | 
|    }
 | 
|  
 | 
| 
 |