| Index: src/spaces.h
 | 
| ===================================================================
 | 
| --- src/spaces.h	(revision 10368)
 | 
| +++ src/spaces.h	(working copy)
 | 
| @@ -295,7 +295,7 @@
 | 
|  
 | 
|  // MemoryChunk represents a memory region owned by a specific space.
 | 
|  // It is divided into the header and the body. Chunk start is always
 | 
| -// 1MB aligned. Start of the body is aligned so it can accomodate
 | 
| +// 1MB aligned. Start of the body is aligned so it can accommodate
 | 
|  // any heap object.
 | 
|  class MemoryChunk {
 | 
|   public:
 | 
| @@ -502,11 +502,9 @@
 | 
|    static const int kObjectStartOffset = kBodyOffset - 1 +
 | 
|        (kObjectStartAlignment - (kBodyOffset - 1) % kObjectStartAlignment);
 | 
|  
 | 
| -  size_t size() const { return size_; }
 | 
| +  intptr_t size() const { return size_; }
 | 
|  
 | 
| -  void set_size(size_t size) {
 | 
| -    size_ = size;
 | 
| -  }
 | 
| +  void set_size(size_t size) { size_ = size; }
 | 
|  
 | 
|    Executability executable() {
 | 
|      return IsFlagSet(IS_EXECUTABLE) ? EXECUTABLE : NOT_EXECUTABLE;
 | 
| @@ -658,7 +656,7 @@
 | 
|    Address ObjectAreaStart() { return address() + kObjectStartOffset; }
 | 
|  
 | 
|    // Returns the end address (exclusive) of the object area in this page.
 | 
| -  Address ObjectAreaEnd() { return address() + Page::kPageSize; }
 | 
| +  Address ObjectAreaEnd() { return address() + size(); }
 | 
|  
 | 
|    // Checks whether an address is page aligned.
 | 
|    static bool IsAlignedToPageSize(Address a) {
 | 
| @@ -677,6 +675,10 @@
 | 
|      return address() + offset;
 | 
|    }
 | 
|  
 | 
| +  // Expand the committed area for pages that are small.  This
 | 
| +  // happens primarily when the VM is newly booted.
 | 
| +  void CommitMore(intptr_t space_needed);
 | 
| +
 | 
|    // ---------------------------------------------------------------------
 | 
|  
 | 
|    // Page size in bytes.  This must be a multiple of the OS page size.
 | 
| @@ -688,6 +690,11 @@
 | 
|    // Object area size in bytes.
 | 
|    static const int kObjectAreaSize = kPageSize - kObjectStartOffset;
 | 
|  
 | 
| +  // The part of the page that is committed until we need more.  If you
 | 
| +  // make this too small then deserializing the initial boot snapshot
 | 
| +  // fails.
 | 
| +  static const int kInitiallyCommittedPartOfPage = kPageSize >> 4;
 | 
| +
 | 
|    // Maximum object size that fits in a page.
 | 
|    static const int kMaxHeapObjectSize = kObjectAreaSize;
 | 
|  
 | 
| @@ -846,12 +853,10 @@
 | 
|      FreeBlock(Address start_arg, size_t size_arg)
 | 
|          : start(start_arg), size(size_arg) {
 | 
|        ASSERT(IsAddressAligned(start, MemoryChunk::kAlignment));
 | 
| -      ASSERT(size >= static_cast<size_t>(Page::kPageSize));
 | 
|      }
 | 
|      FreeBlock(void* start_arg, size_t size_arg)
 | 
|          : start(static_cast<Address>(start_arg)), size(size_arg) {
 | 
|        ASSERT(IsAddressAligned(start, MemoryChunk::kAlignment));
 | 
| -      ASSERT(size >= static_cast<size_t>(Page::kPageSize));
 | 
|      }
 | 
|  
 | 
|      Address start;
 | 
| @@ -947,7 +952,9 @@
 | 
|  
 | 
|    void TearDown();
 | 
|  
 | 
| -  Page* AllocatePage(PagedSpace* owner, Executability executable);
 | 
| +  Page* AllocatePage(intptr_t object_area_size,
 | 
| +                     PagedSpace* owner,
 | 
| +                     Executability executable);
 | 
|  
 | 
|    LargePage* AllocateLargePage(intptr_t object_size,
 | 
|                                        Executability executable,
 | 
| @@ -956,10 +963,14 @@
 | 
|    void Free(MemoryChunk* chunk);
 | 
|  
 | 
|    // Returns the maximum available bytes of heaps.
 | 
| -  intptr_t Available() { return capacity_ < size_ ? 0 : capacity_ - size_; }
 | 
| +  intptr_t Available() {
 | 
| +    return capacity_ < memory_allocator_reserved_ ?
 | 
| +           0 :
 | 
| +           capacity_ - memory_allocator_reserved_;
 | 
| +  }
 | 
|  
 | 
|    // Returns allocated spaces in bytes.
 | 
| -  intptr_t Size() { return size_; }
 | 
| +  intptr_t Size() { return memory_allocator_reserved_; }
 | 
|  
 | 
|    // Returns the maximum available executable bytes of heaps.
 | 
|    intptr_t AvailableExecutable() {
 | 
| @@ -981,6 +992,7 @@
 | 
|  #endif
 | 
|  
 | 
|    MemoryChunk* AllocateChunk(intptr_t body_size,
 | 
| +                             intptr_t committed_body_size,
 | 
|                               Executability executable,
 | 
|                               Space* space);
 | 
|  
 | 
| @@ -988,6 +1000,7 @@
 | 
|                                 size_t alignment,
 | 
|                                 VirtualMemory* controller);
 | 
|    Address AllocateAlignedMemory(size_t requested,
 | 
| +                                size_t committed,
 | 
|                                  size_t alignment,
 | 
|                                  Executability executable,
 | 
|                                  VirtualMemory* controller);
 | 
| @@ -1007,6 +1020,12 @@
 | 
|    // and false otherwise.
 | 
|    bool UncommitBlock(Address start, size_t size);
 | 
|  
 | 
| +  void AllocationBookkeeping(Space* owner,
 | 
| +                             Address base,
 | 
| +                             intptr_t reserved_size,
 | 
| +                             intptr_t committed_size,
 | 
| +                             Executability executable);
 | 
| +
 | 
|    // Zaps a contiguous block of memory [start..(start+size)[ thus
 | 
|    // filling it up with a recognizable non-NULL bit pattern.
 | 
|    void ZapBlock(Address start, size_t size);
 | 
| @@ -1034,7 +1053,7 @@
 | 
|    size_t capacity_executable_;
 | 
|  
 | 
|    // Allocated space size in bytes.
 | 
| -  size_t size_;
 | 
| +  size_t memory_allocator_reserved_;
 | 
|    // Allocated executable space size in bytes.
 | 
|    size_t size_executable_;
 | 
|  
 | 
| @@ -1181,11 +1200,11 @@
 | 
|  
 | 
|  
 | 
|  // An abstraction of the accounting statistics of a page-structured space.
 | 
| -// The 'capacity' of a space is the number of object-area bytes (ie, not
 | 
| +// The 'capacity' of a space is the number of object-area bytes (i.e., not
 | 
|  // including page bookkeeping structures) currently in the space. The 'size'
 | 
|  // of a space is the number of allocated bytes, the 'waste' in the space is
 | 
|  // the number of bytes that are not allocated and not available to
 | 
| -// allocation without reorganizing the space via a GC (eg, small blocks due
 | 
| +// allocation without reorganizing the space via a GC (e.g. small blocks due
 | 
|  // to internal fragmentation, top of page areas in map space), and the bytes
 | 
|  // 'available' is the number of unallocated bytes that are not waste.  The
 | 
|  // capacity is the sum of size, waste, and available.
 | 
| @@ -1198,7 +1217,7 @@
 | 
|   public:
 | 
|    AllocationStats() { Clear(); }
 | 
|  
 | 
| -  // Zero out all the allocation statistics (ie, no capacity).
 | 
| +  // Zero out all the allocation statistics (i.e., no capacity).
 | 
|    void Clear() {
 | 
|      capacity_ = 0;
 | 
|      size_ = 0;
 | 
| @@ -1210,7 +1229,7 @@
 | 
|      waste_ = 0;
 | 
|    }
 | 
|  
 | 
| -  // Reset the allocation statistics (ie, available = capacity with no
 | 
| +  // Reset the allocation statistics (i.e., available = capacity with no
 | 
|    // wasted or allocated bytes).
 | 
|    void Reset() {
 | 
|      size_ = 0;
 | 
| @@ -1341,7 +1360,7 @@
 | 
|    // starting at 'start' is placed on the free list.  The return value is the
 | 
|    // number of bytes that have been lost due to internal fragmentation by
 | 
|    // freeing the block.  Bookkeeping information will be written to the block,
 | 
| -  // ie, its contents will be destroyed.  The start address should be word
 | 
| +  // i.e., its contents will be destroyed.  The start address should be word
 | 
|    // aligned, and the size should be a non-zero multiple of the word size.
 | 
|    int Free(Address start, int size_in_bytes);
 | 
|  
 | 
| @@ -1379,9 +1398,13 @@
 | 
|    static const int kMinBlockSize = 3 * kPointerSize;
 | 
|    static const int kMaxBlockSize = Page::kMaxHeapObjectSize;
 | 
|  
 | 
| -  FreeListNode* PickNodeFromList(FreeListNode** list, int* node_size);
 | 
| +  FreeListNode* PickNodeFromList(FreeListNode** list,
 | 
| +                                 int* node_size,
 | 
| +                                 int minimum_size);
 | 
|  
 | 
| -  FreeListNode* FindNodeFor(int size_in_bytes, int* node_size);
 | 
| +  FreeListNode* FindNodeFor(int size_in_bytes, int* node_size, Address limit);
 | 
| +  FreeListNode* FindAbuttingNode(
 | 
| +      int size_in_bytes, int* node_size, Address limit, FreeListNode** list_head);
 | 
|  
 | 
|    PagedSpace* owner_;
 | 
|    Heap* heap_;
 | 
| @@ -1478,6 +1501,8 @@
 | 
|    // free bytes that were not found at all due to lazy sweeping.
 | 
|    virtual intptr_t Waste() { return accounting_stats_.Waste(); }
 | 
|  
 | 
| +  virtual int ObjectAlignment() { return kPointerSize; }
 | 
| +
 | 
|    // Returns the allocation pointer in this space.
 | 
|    Address top() {
 | 
|      return allocation_info_.top;
 | 
| @@ -1494,7 +1519,8 @@
 | 
|    // the free list or accounted as waste.
 | 
|    // If add_to_freelist is false then just accounting stats are updated and
 | 
|    // no attempt to add area to free list is made.
 | 
| -  int Free(Address start, int size_in_bytes) {
 | 
| +  int AddToFreeLists(Address start, int size_in_bytes) {
 | 
| +    printf("Add to free list: %p (%d bytes)\n", (void*)start, size_in_bytes);
 | 
|      int wasted = free_list_.Free(start, size_in_bytes);
 | 
|      accounting_stats_.DeallocateBytes(size_in_bytes - wasted);
 | 
|      return size_in_bytes - wasted;
 | 
| @@ -1502,6 +1528,7 @@
 | 
|  
 | 
|    // Set space allocation info.
 | 
|    void SetTop(Address top, Address limit) {
 | 
| +    ASSERT(top == NULL || top >= Page::FromAddress(top - 1)->ObjectAreaStart());
 | 
|      ASSERT(top == limit ||
 | 
|             Page::FromAddress(top) == Page::FromAddress(limit - 1));
 | 
|      allocation_info_.top = top;
 | 
| @@ -1567,6 +1594,7 @@
 | 
|      return !first_unswept_page_->is_valid();
 | 
|    }
 | 
|  
 | 
| +  inline bool HasAPage() { return anchor_.next_page() != &anchor_; }
 | 
|    Page* FirstPage() { return anchor_.next_page(); }
 | 
|    Page* LastPage() { return anchor_.prev_page(); }
 | 
|  
 | 
| @@ -1639,20 +1667,15 @@
 | 
|    // Normal allocation information.
 | 
|    AllocationInfo allocation_info_;
 | 
|  
 | 
| -  // Bytes of each page that cannot be allocated.  Possibly non-zero
 | 
| -  // for pages in spaces with only fixed-size objects.  Always zero
 | 
| -  // for pages in spaces with variable sized objects (those pages are
 | 
| -  // padded with free-list nodes).
 | 
| -  int page_extra_;
 | 
| -
 | 
|    bool was_swept_conservatively_;
 | 
|  
 | 
|    Page* first_unswept_page_;
 | 
|  
 | 
| -  // Expands the space by allocating a fixed number of pages. Returns false if
 | 
| -  // it cannot allocate requested number of pages from OS, or if the hard heap
 | 
| -  // size limit has been hit.
 | 
| -  bool Expand();
 | 
| +  // Expands the space by allocating a page. Returns false if it cannot
 | 
| +  // allocate a page from OS, or if the hard heap size limit has been hit.  The
 | 
| +  // new page will have at least enough committed space to satisfy the object
 | 
| +  // size indicated by the allocation_size argument;
 | 
| +  bool Expand(intptr_t allocation_size);
 | 
|  
 | 
|    // Generic fast case allocation function that tries linear allocation at the
 | 
|    // address denoted by top in allocation_info_.
 | 
| @@ -2312,15 +2335,8 @@
 | 
|             intptr_t max_capacity,
 | 
|             AllocationSpace id,
 | 
|             Executability executable)
 | 
| -      : PagedSpace(heap, max_capacity, id, executable) {
 | 
| -    page_extra_ = 0;
 | 
| -  }
 | 
| +      : PagedSpace(heap, max_capacity, id, executable) { }
 | 
|  
 | 
| -  // The limit of allocation for a page in this space.
 | 
| -  virtual Address PageAllocationLimit(Page* page) {
 | 
| -    return page->ObjectAreaEnd();
 | 
| -  }
 | 
| -
 | 
|   public:
 | 
|    TRACK_MEMORY("OldSpace")
 | 
|  };
 | 
| @@ -2346,17 +2362,12 @@
 | 
|               const char* name)
 | 
|        : PagedSpace(heap, max_capacity, id, NOT_EXECUTABLE),
 | 
|          object_size_in_bytes_(object_size_in_bytes),
 | 
| -        name_(name) {
 | 
| -    page_extra_ = Page::kObjectAreaSize % object_size_in_bytes;
 | 
| -  }
 | 
| +        name_(name) { }
 | 
|  
 | 
| -  // The limit of allocation for a page in this space.
 | 
| -  virtual Address PageAllocationLimit(Page* page) {
 | 
| -    return page->ObjectAreaEnd() - page_extra_;
 | 
| -  }
 | 
| -
 | 
|    int object_size_in_bytes() { return object_size_in_bytes_; }
 | 
|  
 | 
| +  virtual int ObjectAlignment() { return object_size_in_bytes_; }
 | 
| +
 | 
|    // Prepares for a mark-compact GC.
 | 
|    virtual void PrepareForMarkCompact();
 | 
|  
 | 
| 
 |