Home | History | Annotate | Download | only in src
      1 // Copyright 2006-2008 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_INL_H_
     29 #define V8_SPACES_INL_H_
     30 
     31 #include "memory.h"
     32 #include "spaces.h"
     33 
     34 namespace v8 {
     35 namespace internal {
     36 
     37 
     38 // -----------------------------------------------------------------------------
     39 // PageIterator
     40 
     41 bool PageIterator::has_next() {
     42   return prev_page_ != stop_page_;
     43 }
     44 
     45 
     46 Page* PageIterator::next() {
     47   ASSERT(has_next());
     48   prev_page_ = (prev_page_ == NULL)
     49                ? space_->first_page_
     50                : prev_page_->next_page();
     51   return prev_page_;
     52 }
     53 
     54 
     55 // -----------------------------------------------------------------------------
     56 // Page
     57 
     58 Page* Page::next_page() {
     59   return MemoryAllocator::GetNextPage(this);
     60 }
     61 
     62 
     63 Address Page::AllocationTop() {
     64   PagedSpace* owner = MemoryAllocator::PageOwner(this);
     65   return owner->PageAllocationTop(this);
     66 }
     67 
     68 
     69 void Page::ClearRSet() {
     70   // This method can be called in all rset states.
     71   memset(RSetStart(), 0, kRSetEndOffset - kRSetStartOffset);
     72 }
     73 
     74 
     75 // Given a 32-bit address, separate its bits into:
     76 // | page address | words (6) | bit offset (5) | pointer alignment (2) |
     77 // The address of the rset word containing the bit for this word is computed as:
     78 //    page_address + words * 4
     79 // For a 64-bit address, if it is:
     80 // | page address | words(5) | bit offset(5) | pointer alignment (3) |
     81 // The address of the rset word containing the bit for this word is computed as:
     82 //    page_address + words * 4 + kRSetOffset.
     83 // The rset is accessed as 32-bit words, and bit offsets in a 32-bit word,
     84 // even on the X64 architecture.
     85 
     86 Address Page::ComputeRSetBitPosition(Address address, int offset,
     87                                      uint32_t* bitmask) {
     88   ASSERT(Page::is_rset_in_use());
     89 
     90   Page* page = Page::FromAddress(address);
     91   uint32_t bit_offset = ArithmeticShiftRight(page->Offset(address) + offset,
     92                                              kPointerSizeLog2);
     93   *bitmask = 1 << (bit_offset % kBitsPerInt);
     94 
     95   Address rset_address =
     96       page->address() + kRSetOffset + (bit_offset / kBitsPerInt) * kIntSize;
     97   // The remembered set address is either in the normal remembered set range
     98   // of a page or else we have a large object page.
     99   ASSERT((page->RSetStart() <= rset_address && rset_address < page->RSetEnd())
    100          || page->IsLargeObjectPage());
    101 
    102   if (rset_address >= page->RSetEnd()) {
    103     // We have a large object page, and the remembered set address is actually
    104     // past the end of the object.
    105 
    106     // The first part of the remembered set is still located at the start of
    107     // the page, but anything after kRSetEndOffset must be relocated to after
    108     // the large object, i.e. after
    109     //   (page->ObjectAreaStart() + object size)
    110     // We do that by adding the difference between the normal RSet's end and
    111     // the object's end.
    112     ASSERT(HeapObject::FromAddress(address)->IsFixedArray());
    113     int fixedarray_length =
    114         FixedArray::SizeFor(Memory::int_at(page->ObjectAreaStart()
    115                                            + Array::kLengthOffset));
    116     rset_address += kObjectStartOffset - kRSetEndOffset + fixedarray_length;
    117   }
    118   return rset_address;
    119 }
    120 
    121 
    122 void Page::SetRSet(Address address, int offset) {
    123   uint32_t bitmask = 0;
    124   Address rset_address = ComputeRSetBitPosition(address, offset, &bitmask);
    125   Memory::uint32_at(rset_address) |= bitmask;
    126 
    127   ASSERT(IsRSetSet(address, offset));
    128 }
    129 
    130 
    131 // Clears the corresponding remembered set bit for a given address.
    132 void Page::UnsetRSet(Address address, int offset) {
    133   uint32_t bitmask = 0;
    134   Address rset_address = ComputeRSetBitPosition(address, offset, &bitmask);
    135   Memory::uint32_at(rset_address) &= ~bitmask;
    136 
    137   ASSERT(!IsRSetSet(address, offset));
    138 }
    139 
    140 
    141 bool Page::IsRSetSet(Address address, int offset) {
    142   uint32_t bitmask = 0;
    143   Address rset_address = ComputeRSetBitPosition(address, offset, &bitmask);
    144   return (Memory::uint32_at(rset_address) & bitmask) != 0;
    145 }
    146 
    147 
    148 // -----------------------------------------------------------------------------
    149 // MemoryAllocator
    150 
    151 bool MemoryAllocator::IsValidChunk(int chunk_id) {
    152   if (!IsValidChunkId(chunk_id)) return false;
    153 
    154   ChunkInfo& c = chunks_[chunk_id];
    155   return (c.address() != NULL) && (c.size() != 0) && (c.owner() != NULL);
    156 }
    157 
    158 
    159 bool MemoryAllocator::IsValidChunkId(int chunk_id) {
    160   return (0 <= chunk_id) && (chunk_id < max_nof_chunks_);
    161 }
    162 
    163 
    164 bool MemoryAllocator::IsPageInSpace(Page* p, PagedSpace* space) {
    165   ASSERT(p->is_valid());
    166 
    167   int chunk_id = GetChunkId(p);
    168   if (!IsValidChunkId(chunk_id)) return false;
    169 
    170   ChunkInfo& c = chunks_[chunk_id];
    171   return (c.address() <= p->address()) &&
    172          (p->address() < c.address() + c.size()) &&
    173          (space == c.owner());
    174 }
    175 
    176 
    177 Page* MemoryAllocator::GetNextPage(Page* p) {
    178   ASSERT(p->is_valid());
    179   intptr_t raw_addr = p->opaque_header & ~Page::kPageAlignmentMask;
    180   return Page::FromAddress(AddressFrom<Address>(raw_addr));
    181 }
    182 
    183 
    184 int MemoryAllocator::GetChunkId(Page* p) {
    185   ASSERT(p->is_valid());
    186   return static_cast<int>(p->opaque_header & Page::kPageAlignmentMask);
    187 }
    188 
    189 
    190 void MemoryAllocator::SetNextPage(Page* prev, Page* next) {
    191   ASSERT(prev->is_valid());
    192   int chunk_id = GetChunkId(prev);
    193   ASSERT_PAGE_ALIGNED(next->address());
    194   prev->opaque_header = OffsetFrom(next->address()) | chunk_id;
    195 }
    196 
    197 
    198 PagedSpace* MemoryAllocator::PageOwner(Page* page) {
    199   int chunk_id = GetChunkId(page);
    200   ASSERT(IsValidChunk(chunk_id));
    201   return chunks_[chunk_id].owner();
    202 }
    203 
    204 
    205 bool MemoryAllocator::InInitialChunk(Address address) {
    206   if (initial_chunk_ == NULL) return false;
    207 
    208   Address start = static_cast<Address>(initial_chunk_->address());
    209   return (start <= address) && (address < start + initial_chunk_->size());
    210 }
    211 
    212 
    213 #ifdef ENABLE_HEAP_PROTECTION
    214 
    215 void MemoryAllocator::Protect(Address start, size_t size) {
    216   OS::Protect(start, size);
    217 }
    218 
    219 
    220 void MemoryAllocator::Unprotect(Address start,
    221                                 size_t size,
    222                                 Executability executable) {
    223   OS::Unprotect(start, size, executable);
    224 }
    225 
    226 
    227 void MemoryAllocator::ProtectChunkFromPage(Page* page) {
    228   int id = GetChunkId(page);
    229   OS::Protect(chunks_[id].address(), chunks_[id].size());
    230 }
    231 
    232 
    233 void MemoryAllocator::UnprotectChunkFromPage(Page* page) {
    234   int id = GetChunkId(page);
    235   OS::Unprotect(chunks_[id].address(), chunks_[id].size(),
    236                 chunks_[id].owner()->executable() == EXECUTABLE);
    237 }
    238 
    239 #endif
    240 
    241 
    242 // --------------------------------------------------------------------------
    243 // PagedSpace
    244 
    245 bool PagedSpace::Contains(Address addr) {
    246   Page* p = Page::FromAddress(addr);
    247   ASSERT(p->is_valid());
    248 
    249   return MemoryAllocator::IsPageInSpace(p, this);
    250 }
    251 
    252 
    253 // Try linear allocation in the page of alloc_info's allocation top.  Does
    254 // not contain slow case logic (eg, move to the next page or try free list
    255 // allocation) so it can be used by all the allocation functions and for all
    256 // the paged spaces.
    257 HeapObject* PagedSpace::AllocateLinearly(AllocationInfo* alloc_info,
    258                                          int size_in_bytes) {
    259   Address current_top = alloc_info->top;
    260   Address new_top = current_top + size_in_bytes;
    261   if (new_top > alloc_info->limit) return NULL;
    262 
    263   alloc_info->top = new_top;
    264   ASSERT(alloc_info->VerifyPagedAllocation());
    265   accounting_stats_.AllocateBytes(size_in_bytes);
    266   return HeapObject::FromAddress(current_top);
    267 }
    268 
    269 
    270 // Raw allocation.
    271 Object* PagedSpace::AllocateRaw(int size_in_bytes) {
    272   ASSERT(HasBeenSetup());
    273   ASSERT_OBJECT_SIZE(size_in_bytes);
    274   HeapObject* object = AllocateLinearly(&allocation_info_, size_in_bytes);
    275   if (object != NULL) return object;
    276 
    277   object = SlowAllocateRaw(size_in_bytes);
    278   if (object != NULL) return object;
    279 
    280   return Failure::RetryAfterGC(size_in_bytes, identity());
    281 }
    282 
    283 
    284 // Reallocating (and promoting) objects during a compacting collection.
    285 Object* PagedSpace::MCAllocateRaw(int size_in_bytes) {
    286   ASSERT(HasBeenSetup());
    287   ASSERT_OBJECT_SIZE(size_in_bytes);
    288   HeapObject* object = AllocateLinearly(&mc_forwarding_info_, size_in_bytes);
    289   if (object != NULL) return object;
    290 
    291   object = SlowMCAllocateRaw(size_in_bytes);
    292   if (object != NULL) return object;
    293 
    294   return Failure::RetryAfterGC(size_in_bytes, identity());
    295 }
    296 
    297 
    298 // -----------------------------------------------------------------------------
    299 // LargeObjectChunk
    300 
    301 HeapObject* LargeObjectChunk::GetObject() {
    302   // Round the chunk address up to the nearest page-aligned address
    303   // and return the heap object in that page.
    304   Page* page = Page::FromAddress(RoundUp(address(), Page::kPageSize));
    305   return HeapObject::FromAddress(page->ObjectAreaStart());
    306 }
    307 
    308 
    309 // -----------------------------------------------------------------------------
    310 // LargeObjectSpace
    311 
    312 int LargeObjectSpace::ExtraRSetBytesFor(int object_size) {
    313   int extra_rset_bits =
    314       RoundUp((object_size - Page::kObjectAreaSize) / kPointerSize,
    315               kBitsPerInt);
    316   return extra_rset_bits / kBitsPerByte;
    317 }
    318 
    319 
    320 Object* NewSpace::AllocateRawInternal(int size_in_bytes,
    321                                       AllocationInfo* alloc_info) {
    322   Address new_top = alloc_info->top + size_in_bytes;
    323   if (new_top > alloc_info->limit) return Failure::RetryAfterGC(size_in_bytes);
    324 
    325   Object* obj = HeapObject::FromAddress(alloc_info->top);
    326   alloc_info->top = new_top;
    327 #ifdef DEBUG
    328   SemiSpace* space =
    329       (alloc_info == &allocation_info_) ? &to_space_ : &from_space_;
    330   ASSERT(space->low() <= alloc_info->top
    331          && alloc_info->top <= space->high()
    332          && alloc_info->limit == space->high());
    333 #endif
    334   return obj;
    335 }
    336 
    337 
    338 bool FreeListNode::IsFreeListNode(HeapObject* object) {
    339   return object->map() == Heap::raw_unchecked_byte_array_map()
    340       || object->map() == Heap::raw_unchecked_one_pointer_filler_map()
    341       || object->map() == Heap::raw_unchecked_two_pointer_filler_map();
    342 }
    343 
    344 } }  // namespace v8::internal
    345 
    346 #endif  // V8_SPACES_INL_H_
    347