• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
has_next()41 bool PageIterator::has_next() {
42   return prev_page_ != stop_page_;
43 }
44 
45 
next()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 
next_page()58 Page* Page::next_page() {
59   return MemoryAllocator::GetNextPage(this);
60 }
61 
62 
AllocationTop()63 Address Page::AllocationTop() {
64   PagedSpace* owner = MemoryAllocator::PageOwner(this);
65   return owner->PageAllocationTop(this);
66 }
67 
68 
ClearRSet()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 
ComputeRSetBitPosition(Address address,int offset,uint32_t * bitmask)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 
SetRSet(Address address,int offset)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.
UnsetRSet(Address address,int offset)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 
IsRSetSet(Address address,int offset)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 
IsValidChunk(int chunk_id)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 
IsValidChunkId(int chunk_id)159 bool MemoryAllocator::IsValidChunkId(int chunk_id) {
160   return (0 <= chunk_id) && (chunk_id < max_nof_chunks_);
161 }
162 
163 
IsPageInSpace(Page * p,PagedSpace * space)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 
GetNextPage(Page * p)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 
GetChunkId(Page * p)184 int MemoryAllocator::GetChunkId(Page* p) {
185   ASSERT(p->is_valid());
186   return static_cast<int>(p->opaque_header & Page::kPageAlignmentMask);
187 }
188 
189 
SetNextPage(Page * prev,Page * next)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 
PageOwner(Page * page)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 
InInitialChunk(Address address)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 
Protect(Address start,size_t size)215 void MemoryAllocator::Protect(Address start, size_t size) {
216   OS::Protect(start, size);
217 }
218 
219 
Unprotect(Address start,size_t size,Executability executable)220 void MemoryAllocator::Unprotect(Address start,
221                                 size_t size,
222                                 Executability executable) {
223   OS::Unprotect(start, size, executable);
224 }
225 
226 
ProtectChunkFromPage(Page * page)227 void MemoryAllocator::ProtectChunkFromPage(Page* page) {
228   int id = GetChunkId(page);
229   OS::Protect(chunks_[id].address(), chunks_[id].size());
230 }
231 
232 
UnprotectChunkFromPage(Page * page)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 
Contains(Address addr)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.
AllocateLinearly(AllocationInfo * alloc_info,int size_in_bytes)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.
AllocateRaw(int size_in_bytes)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.
MCAllocateRaw(int size_in_bytes)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 
GetObject()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 
ExtraRSetBytesFor(int object_size)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 
AllocateRawInternal(int size_in_bytes,AllocationInfo * alloc_info)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 
IsFreeListNode(HeapObject * object)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